hdkv
/
i2_bot
Archived
1
Fork 0

Massive refactoring for future development

master
Vladimir Hodakov 2017-11-21 06:06:32 +04:00
parent f5d801b768
commit dfe0d08ecc
45 changed files with 742 additions and 640 deletions

View File

@ -6,15 +6,17 @@ 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/broadcaster"
"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/pokedexer"
"lab.pztrn.name/fat0troll/i2_bot/lib/router"
"lab.pztrn.name/fat0troll/i2_bot/lib/squader"
"lab.pztrn.name/fat0troll/i2_bot/lib/statistics"
"lab.pztrn.name/fat0troll/i2_bot/lib/talkers"
"lab.pztrn.name/fat0troll/i2_bot/lib/users"
"lab.pztrn.name/fat0troll/i2_bot/lib/welcomer"
"time"
)
@ -30,13 +32,15 @@ func main() {
migrations.New(c)
c.RunDatabaseMigrations()
forwarder.New(c)
parsers.New(c)
pokedexer.New(c)
pinner.New(c)
talkers.New(c)
getters.New(c)
broadcaster.New(c)
welcomer.New(c)
chatter.New(c)
squader.New(c)
users.New(c)
statistics.New(c)
c.Log.Info("=======================")
c.Log.Info("= i2_bot initialized. =")

View File

@ -6,17 +6,19 @@ package appcontext
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
"github.com/jmoiron/sqlx"
"lab.pztrn.name/fat0troll/i2_bot/lib/broadcaster/broadcasterinterface"
"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"
"lab.pztrn.name/fat0troll/i2_bot/lib/getters/gettersinterface"
"lab.pztrn.name/fat0troll/i2_bot/lib/migrations/migrationsinterface"
"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/pokedexer/pokedexerinterface"
"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/statistics/statisticsinterface"
"lab.pztrn.name/fat0troll/i2_bot/lib/talkers/talkersinterface"
"lab.pztrn.name/fat0troll/i2_bot/lib/users/usersinterface"
"lab.pztrn.name/fat0troll/i2_bot/lib/welcomer/welcomerinterface"
"lab.pztrn.name/golibs/mogrus"
"os"
@ -24,20 +26,22 @@ import (
// Context is an application context struct
type Context struct {
Cfg *config.Config
Log *mogrus.LoggerHandler
Bot *tgbotapi.BotAPI
Forwarder forwarderinterface.ForwarderInterface
Migrations migrationsinterface.MigrationsInterface
Router routerinterface.RouterInterface
Parsers parsersinterface.ParsersInterface
Db *sqlx.DB
Talkers talkersinterface.TalkersInterface
Getters gettersinterface.GettersInterface
Welcomer welcomerinterface.WelcomerInterface
Pinner pinnerinterface.PinnerInterface
Chatter chatterinterface.ChatterInterface
Squader squaderinterface.SquaderInterface
Cfg *config.Config
Log *mogrus.LoggerHandler
Bot *tgbotapi.BotAPI
Forwarder forwarderinterface.ForwarderInterface
Migrations migrationsinterface.MigrationsInterface
Router routerinterface.RouterInterface
Pokedexer pokedexerinterface.PokedexerInterface
Db *sqlx.DB
Talkers talkersinterface.TalkersInterface
Broadcaster broadcasterinterface.BroadcasterInterface
Welcomer welcomerinterface.WelcomerInterface
Pinner pinnerinterface.PinnerInterface
Chatter chatterinterface.ChatterInterface
Squader squaderinterface.SquaderInterface
Users usersinterface.UsersInterface
Statistics statisticsinterface.StatisticsInterface
}
// Init is a initialization function for context
@ -75,9 +79,9 @@ func (c *Context) RegisterMigrationsInterface(mi migrationsinterface.MigrationsI
c.Migrations.Init()
}
// RegisterParsersInterface registering parsers interface in application
func (c *Context) RegisterParsersInterface(pi parsersinterface.ParsersInterface) {
c.Parsers = pi
// RegisterPokedexerInterface registering parsers interface in application
func (c *Context) RegisterPokedexerInterface(pi pokedexerinterface.PokedexerInterface) {
c.Pokedexer = pi
}
// RegisterTalkersInterface registering talkers interface in application
@ -86,10 +90,10 @@ func (c *Context) RegisterTalkersInterface(ti talkersinterface.TalkersInterface)
c.Talkers.Init()
}
// RegisterGettersInterface registering getters interface in application
func (c *Context) RegisterGettersInterface(gi gettersinterface.GettersInterface) {
c.Getters = gi
c.Getters.Init()
// RegisterBroadcasterInterface registering broadcaster interface in application
func (c *Context) RegisterBroadcasterInterface(bi broadcasterinterface.BroadcasterInterface) {
c.Broadcaster = bi
c.Broadcaster.Init()
}
// RegisterWelcomerInterface registering welcomer interface in application
@ -122,6 +126,18 @@ func (c *Context) RegisterSquaderInterface(si squaderinterface.SquaderInterface)
c.Squader.Init()
}
// RegisterUsersInterface registers users interface in application
func (c *Context) RegisterUsersInterface(ui usersinterface.UsersInterface) {
c.Users = ui
c.Users.Init()
}
// RegisterStatisticsInterface registers statistics interface in application
func (c *Context) RegisterStatisticsInterface(si statisticsinterface.StatisticsInterface) {
c.Statistics = si
c.Statistics.Init()
}
// RunDatabaseMigrations applies migrations on bot's startup
func (c *Context) RunDatabaseMigrations() {
c.Migrations.SetDialect("mysql")

View File

@ -1,15 +1,14 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package getters
package broadcaster
import (
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
"time"
)
// CreateBroadcastMessage creates broadcast message item in database
func (g *Getters) CreateBroadcastMessage(playerRaw *dbmapping.Player, messageBody string, broadcastType string) (dbmapping.Broadcast, bool) {
func (b *Broadcaster) createBroadcastMessage(playerRaw *dbmapping.Player, messageBody string, broadcastType string) (dbmapping.Broadcast, bool) {
messageRaw := dbmapping.Broadcast{}
messageRaw.Text = messageBody
messageRaw.Status = "new"
@ -30,8 +29,7 @@ func (g *Getters) CreateBroadcastMessage(playerRaw *dbmapping.Player, messageBod
return messageRaw, true
}
// GetBroadcastMessageByID returns dbmapping.Broadcast instance with given ID.
func (g *Getters) GetBroadcastMessageByID(messageID int) (dbmapping.Broadcast, bool) {
func (b *Broadcaster) getBroadcastMessageByID(messageID int) (dbmapping.Broadcast, bool) {
messageRaw := dbmapping.Broadcast{}
err := c.Db.Get(&messageRaw, c.Db.Rebind("SELECT * FROM broadcasts WHERE id=?"), messageID)
if err != nil {
@ -42,8 +40,7 @@ func (g *Getters) GetBroadcastMessageByID(messageID int) (dbmapping.Broadcast, b
return messageRaw, true
}
// UpdateBroadcastMessageStatus updates broadcast message status
func (g *Getters) UpdateBroadcastMessageStatus(messageID int, messageStatus string) (dbmapping.Broadcast, bool) {
func (b *Broadcaster) updateBroadcastMessageStatus(messageID int, messageStatus string) (dbmapping.Broadcast, bool) {
messageRaw := dbmapping.Broadcast{}
err := c.Db.Get(&messageRaw, c.Db.Rebind("SELECT * FROM broadcasts WHERE id=?"), messageID)
if err != nil {

View File

@ -0,0 +1,17 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package broadcasterinterface
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
)
// BroadcasterInterface implements Broadcaster for importing via appcontex
type BroadcasterInterface interface {
Init()
AdminBroadcastMessageCompose(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
AdminBroadcastMessageSend(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
}

View File

@ -0,0 +1,28 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package broadcaster
import (
"lab.pztrn.name/fat0troll/i2_bot/lib/appcontext"
"lab.pztrn.name/fat0troll/i2_bot/lib/broadcaster/broadcasterinterface"
)
var (
c *appcontext.Context
)
// Broadcaster is a function-handling struct for broadcaster
type Broadcaster struct{}
// New is a appcontext initialization function
func New(ac *appcontext.Context) {
c = ac
b := &Broadcaster{}
c.RegisterBroadcasterInterface(broadcasterinterface.BroadcasterInterface(b))
}
// Init is an initialization function for talkers
func (b *Broadcaster) Init() {
c.Log.Info("Initializing Broadcaster...")
}

View File

@ -0,0 +1,47 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package broadcaster
import (
"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
func (b *Broadcaster) AdminBroadcastMessageCompose(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
broadcastingMessageBody := strings.Replace(update.Message.Text, "/send_all ", "", 1)
messageRaw, ok := b.createBroadcastMessage(playerRaw, broadcastingMessageBody, "all")
if !ok {
return "fail"
}
message := "Сообщение сохранено в базу.\n"
message += "Выглядеть оно будет так:"
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
broadcastingMessage := "*Привет, %username%!*\n\n"
broadcastingMessage += "*Важное сообщение от администратора " + update.Message.From.FirstName + " " + update.Message.From.LastName + "* (@" + update.Message.From.UserName + ")\n\n"
broadcastingMessage += messageRaw.Text
msg = tgbotapi.NewMessage(update.Message.Chat.ID, broadcastingMessage)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
message = "Чтобы отправить сообщение всем, отправь команду /send\\_confirm " + strconv.Itoa(messageRaw.ID)
msg = tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
return "ok"
}

59
lib/broadcaster/sender.go Normal file
View File

@ -0,0 +1,59 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package broadcaster
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
"strconv"
"strings"
)
// AdminBroadcastMessageSend sends saved message to all private chats
func (b *Broadcaster) AdminBroadcastMessageSend(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
messageNum := strings.Replace(update.Message.Text, "/send_confirm ", "", 1)
messageNumInt, _ := strconv.Atoi(messageNum)
messageRaw, ok := b.getBroadcastMessageByID(messageNumInt)
if !ok {
return "fail"
}
if messageRaw.AuthorID != playerRaw.ID {
return "fail"
}
if messageRaw.Status != "new" {
return "fail"
}
broadcastingMessageBody := messageRaw.Text
privateChats, ok := c.Chatter.GetAllPrivateChats()
if !ok {
return "fail"
}
for i := range privateChats {
chat := privateChats[i]
broadcastingMessage := "*Привет, " + chat.Name + "!*\n\n"
broadcastingMessage += "*Важное сообщение от администратора " + update.Message.From.FirstName + " " + update.Message.From.LastName + "* (@" + update.Message.From.UserName + ")\n\n"
broadcastingMessage += broadcastingMessageBody
msg := tgbotapi.NewMessage(int64(chat.TelegramID), broadcastingMessage)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
}
messageRaw, ok = b.updateBroadcastMessageStatus(messageRaw.ID, "sent")
if !ok {
return "fail"
}
message := "Сообщение всем отправлено. Надеюсь, пользователи бота за него тебя не убьют.\n"
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
return "ok"
}

View File

@ -10,7 +10,7 @@ import (
"path/filepath"
)
const VERSION = "0.35"
const VERSION = "0.51"
// DatabaseConnection handles database connection settings in config.yaml
type DatabaseConnection struct {

View File

@ -24,5 +24,5 @@ func New(ac *appcontext.Context) {
// Init is a initialization function for package
func (f *Forwarder) Init() {
c.Log.Info("Initializing forwarder...")
c.Log.Info("Initializing Forwarder...")
}

View File

@ -20,33 +20,14 @@ func (f *Forwarder) ProcessForward(update *tgbotapi.Update, playerRaw *dbmapping
case pokememeMsg.MatchString(text):
c.Log.Debug("Pokememe posted!")
if playerRaw.LeagueID == 1 {
status := c.Parsers.ParsePokememe(text, playerRaw)
switch status {
case "ok":
c.Talkers.PokememeAddSuccessMessage(update)
return "ok"
case "dup":
c.Talkers.PokememeAddDuplicateMessage(update)
return "ok"
case "fail":
c.Talkers.PokememeAddFailureMessage(update)
return "fail"
}
return c.Pokedexer.ParsePokememe(update, playerRaw)
} else {
c.Talkers.AnyMessageUnauthorized(update)
return "fail"
}
case profileMsg.MatchString(text):
c.Log.Debug("Profile posted!")
status := c.Parsers.ParseProfile(update, playerRaw)
switch status {
case "ok":
c.Talkers.ProfileAddSuccessMessage(update)
return "ok"
case "fail":
c.Talkers.ProfileAddFailureMessage(update)
return "fail"
}
return c.Users.ParseProfile(update, playerRaw)
default:
c.Log.Debug(text)
}

View File

@ -1,28 +0,0 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package getters
import (
"lab.pztrn.name/fat0troll/i2_bot/lib/appcontext"
"lab.pztrn.name/fat0troll/i2_bot/lib/getters/gettersinterface"
)
var (
c *appcontext.Context
)
// Getters is a function-handling struct for package getters.
type Getters struct{}
// New is an initialization function for appcontext
func New(ac *appcontext.Context) {
c = ac
g := &Getters{}
c.RegisterGettersInterface(gettersinterface.GettersInterface(g))
}
// Init is a initialization function for package
func (g *Getters) Init() {
c.Log.Info("Initializing getters...")
}

View File

@ -1,24 +0,0 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package gettersinterface
import (
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
)
// GettersInterface implements Getters for importing via appcontext.
type GettersInterface interface {
Init()
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)
GetOrCreatePlayer(telegramID int) (dbmapping.Player, bool)
GetPlayerByID(playerID int) (dbmapping.Player, bool)
PlayerBetterThan(playerRaw *dbmapping.Player, powerLevel string) bool
GetProfile(playerID int) (dbmapping.Profile, bool)
GetPokememes() ([]dbmapping.PokememeFull, bool)
GetBestPokememes(playerID int) ([]dbmapping.PokememeFull, bool)
GetPokememeByID(pokememeID string) (dbmapping.PokememeFull, bool)
PossibilityRequiredPokeballs(location int, grade int, lvl int) (float64, int)
}

View File

@ -1,20 +0,0 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package getters
import (
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
)
// GetProfile returns last saved profile of player
func (g *Getters) GetProfile(playerID int) (dbmapping.Profile, bool) {
profileRaw := dbmapping.Profile{}
err := c.Db.Get(&profileRaw, c.Db.Rebind("SELECT * FROM profiles WHERE player_id=? ORDER BY created_at DESC LIMIT 1"), playerID)
if err != nil {
c.Log.Error(err)
return profileRaw, false
}
return profileRaw, true
}

View File

@ -1,18 +0,0 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package parsersinterface
import (
// 3rd party
"github.com/go-telegram-bot-api/telegram-bot-api"
// local
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
)
// ParsersInterface implements Parsers for importing via appcontext.
type ParsersInterface interface {
ParsePokememe(text string, playerRaw *dbmapping.Player) string
ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
ReturnPoints(points int) string
}

View File

@ -1,24 +1,24 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package parsers
package pokedexer
import (
// local
"lab.pztrn.name/fat0troll/i2_bot/lib/appcontext"
"lab.pztrn.name/fat0troll/i2_bot/lib/parsers/parsersinterface"
"lab.pztrn.name/fat0troll/i2_bot/lib/pokedexer/pokedexerinterface"
)
var (
c *appcontext.Context
)
// Parsers is a function-handling struct for package parsers
type Parsers struct{}
// Pokedexer is a function-handling struct for package pokedexer
type Pokedexer struct{}
// New is an initialization function for appcontext
func New(ac *appcontext.Context) {
c = ac
p := &Parsers{}
c.RegisterParsersInterface(parsersinterface.ParsersInterface(p))
p := &Pokedexer{}
c.RegisterPokedexerInterface(pokedexerinterface.PokedexerInterface(p))
}

View File

@ -1,7 +1,7 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package getters
package pokedexer
import (
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
@ -10,7 +10,7 @@ import (
// Internal functions
func (g *Getters) formFullPokememes(pokememes []dbmapping.Pokememe) ([]dbmapping.PokememeFull, bool) {
func (p *Pokedexer) formFullPokememes(pokememes []dbmapping.Pokememe) ([]dbmapping.PokememeFull, bool) {
pokememesArray := []dbmapping.PokememeFull{}
elements := []dbmapping.Element{}
err := c.Db.Select(&elements, "SELECT * FROM elements")
@ -75,7 +75,7 @@ func (g *Getters) formFullPokememes(pokememes []dbmapping.Pokememe) ([]dbmapping
// External functions
// GetPokememes returns all existing pokememes, known by bot
func (g *Getters) GetPokememes() ([]dbmapping.PokememeFull, bool) {
func (p *Pokedexer) GetPokememes() ([]dbmapping.PokememeFull, bool) {
pokememesArray := []dbmapping.PokememeFull{}
pokememes := []dbmapping.Pokememe{}
err := c.Db.Select(&pokememes, "SELECT * FROM pokememes ORDER BY grade asc, name asc")
@ -84,18 +84,17 @@ func (g *Getters) GetPokememes() ([]dbmapping.PokememeFull, bool) {
return pokememesArray, false
}
pokememesArray, ok := g.formFullPokememes(pokememes)
pokememesArray, ok := p.formFullPokememes(pokememes)
return pokememesArray, ok
}
// GetBestPokememes returns all pokememes, which will be good for player to catch
func (g *Getters) GetBestPokememes(playerID int) ([]dbmapping.PokememeFull, bool) {
func (p *Pokedexer) getBestPokememes(playerID int) ([]dbmapping.PokememeFull, bool) {
pokememesArray := []dbmapping.PokememeFull{}
playerRaw, ok := g.GetPlayerByID(playerID)
playerRaw, ok := c.Users.GetPlayerByID(playerID)
if !ok {
return pokememesArray, ok
}
profileRaw, ok := g.GetProfile(playerID)
profileRaw, ok := c.Users.GetProfile(playerID)
if !ok {
return pokememesArray, ok
}
@ -112,12 +111,12 @@ func (g *Getters) GetBestPokememes(playerID int) ([]dbmapping.PokememeFull, bool
return pokememesArray, false
}
pokememesArray, ok = g.formFullPokememes(pokememes)
pokememesArray, ok = p.formFullPokememes(pokememes)
return pokememesArray, ok
}
// GetPokememeByUD returns single pokememe based on internal ID in database
func (g *Getters) GetPokememeByID(pokememeID string) (dbmapping.PokememeFull, bool) {
// GetPokememeByID returns single pokememe based on internal ID in database
func (p *Pokedexer) GetPokememeByID(pokememeID string) (dbmapping.PokememeFull, bool) {
fullPokememe := dbmapping.PokememeFull{}
pokememe := dbmapping.Pokememe{}
err := c.Db.Get(&pokememe, c.Db.Rebind("SELECT * FROM pokememes WHERE id=?"), pokememeID)

View File

@ -1,9 +1,10 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package parsers
package pokedexer
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
"regexp"
"strconv"
@ -11,28 +12,9 @@ import (
"time"
)
// Internal functions
func (p *Parsers) getPoints(pointsStr string) int {
value := 0
if strings.HasSuffix(pointsStr, "K") {
valueNumber := strings.Replace(pointsStr, "K", "", 1)
valueFloat, _ := strconv.ParseFloat(valueNumber, 64)
value = int(valueFloat * 1000)
} else if strings.HasSuffix(pointsStr, "M") {
valueNumber := strings.Replace(pointsStr, "M", "", 1)
valueFloat, _ := strconv.ParseFloat(valueNumber, 64)
value = int(valueFloat * 1000000)
} else {
value, _ = strconv.Atoi(pointsStr)
}
return value
}
// External functions
// ParsePokememe parses pokememe, forwarded from PokememeBroBot, to database
func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string {
func (p *Pokedexer) ParsePokememe(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
text := update.Message.Text
var defendablePokememe = false
pokememeStringsArray := strings.Split(text, "\n")
pokememeRunesArray := make([][]rune, 0)
@ -58,6 +40,7 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
err := c.Db.Select(&elements, "SELECT * FROM elements WHERE symbol IN ('"+strings.Join(elementEmojis, "', '")+"')")
if err != nil {
c.Log.Error(err.Error())
p.pokememeAddFailureMessage(update)
return "fail"
}
@ -67,6 +50,7 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
if len(hitPoints) != 3 {
c.Log.Error("Can't parse hitpoints!")
c.Log.Debug(pokememeRunesArray[5])
p.pokememeAddFailureMessage(update)
return "fail"
}
@ -84,6 +68,7 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
if len(defenceMatch) < 1 {
c.Log.Error("Can't parse defence!")
c.Log.Debug(pokememeRunesArray[6])
p.pokememeAddFailureMessage(update)
return "fail"
}
defence = defenceMatch[0]
@ -91,6 +76,7 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
if len(priceMatch) < 1 {
c.Log.Error("Can't parse price!")
c.Log.Debug(pokememeRunesArray[7])
p.pokememeAddFailureMessage(update)
return "fail"
}
price = priceMatch[0]
@ -98,18 +84,21 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
if len(locationsPrepare) < 2 {
c.Log.Error("Can't parse locations!")
c.Log.Debug(pokememeRunesArray[8])
p.pokememeAddFailureMessage(update)
return "fail"
}
locationsNames := strings.Split(locationsPrepare[1], ", ")
if len(locationsNames) < 1 {
c.Log.Error("Can't parse locations!")
c.Log.Debug(locationsPrepare)
p.pokememeAddFailureMessage(update)
return "fail"
}
err2 := c.Db.Select(&locations, "SELECT * FROM locations WHERE name IN ('"+strings.Join(locationsNames, "', '")+"')")
if err2 != nil {
c.Log.Error(err2.Error())
p.pokememeAddFailureMessage(update)
return "fail"
}
if strings.HasSuffix(string(pokememeRunesArray[9]), "Можно") {
@ -123,6 +112,7 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
if len(priceMatch) < 1 {
c.Log.Error("Can't parse price!")
c.Log.Debug(pokememeRunesArray[6])
p.pokememeAddFailureMessage(update)
return "fail"
}
price = priceMatch[0]
@ -130,18 +120,21 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
if len(locationsPrepare) < 2 {
c.Log.Error("Can't parse locations!")
c.Log.Debug(pokememeRunesArray[7])
p.pokememeAddFailureMessage(update)
return "fail"
}
locationsNames := strings.Split(locationsPrepare[1], ", ")
if len(locationsNames) < 1 {
c.Log.Error("Can't parse locations!")
c.Log.Debug(locationsPrepare)
p.pokememeAddFailureMessage(update)
return "fail"
}
err2 := c.Db.Select(&locations, "SELECT * FROM locations WHERE name IN ('"+strings.Join(locationsNames, "', '")+"')")
if err2 != nil {
c.Log.Error(err2.Error())
p.pokememeAddFailureMessage(update)
return "fail"
}
if strings.HasSuffix(string(pokememeRunesArray[8]), "Можно") {
@ -184,15 +177,16 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
c.Log.Debug("Adding new pokememe...")
} else {
c.Log.Info("This pokememe already exist. Return specific error.")
p.pokememeAddDuplicateMessage(update)
return "dup"
}
gradeInt, _ := strconv.Atoi(grade)
attackInt := p.getPoints(hitPoints[0])
hpInt := p.getPoints(hitPoints[1])
mpInt := p.getPoints(hitPoints[2])
defenceInt := p.getPoints(defence)
priceInt := p.getPoints(price)
attackInt := c.Statistics.GetPoints(hitPoints[0])
hpInt := c.Statistics.GetPoints(hitPoints[1])
mpInt := c.Statistics.GetPoints(hitPoints[2])
defenceInt := c.Statistics.GetPoints(defence)
priceInt := c.Statistics.GetPoints(price)
pokememe.Grade = gradeInt
pokememe.Name = name
@ -214,6 +208,7 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
_, err4 := c.Db.NamedExec("INSERT INTO pokememes VALUES(NULL, :grade, :name, :description, :attack, :hp, :mp, :defence, :price, :purchaseable, :image_url, :player_id, :created_at)", &pokememe)
if err4 != nil {
c.Log.Error(err4.Error())
p.pokememeAddFailureMessage(update)
return "fail"
}
@ -221,6 +216,7 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
err5 := c.Db.Get(&pokememe, c.Db.Rebind("SELECT * FROM pokememes WHERE grade='"+grade+"' AND name='"+name+"';"))
if err5 != nil {
c.Log.Error("Pokememe isn't added!")
p.pokememeAddFailureMessage(update)
return "fail"
}
for i := range elements {
@ -232,6 +228,7 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
_, err6 := c.Db.NamedExec("INSERT INTO pokememes_elements VALUES(NULL, :pokememe_id, :element_id, :created_at)", &link)
if err6 != nil {
c.Log.Error(err6.Error())
p.pokememeAddFailureMessage(update)
return "fail"
}
}
@ -244,23 +241,11 @@ func (p *Parsers) ParsePokememe(text string, playerRaw *dbmapping.Player) string
_, err7 := c.Db.NamedExec("INSERT INTO pokememes_locations VALUES(NULL, :pokememe_id, :location_id, :created_at)", &link)
if err7 != nil {
c.Log.Error(err7.Error())
p.pokememeAddFailureMessage(update)
return "fail"
}
}
p.pokememeAddSuccessMessage(update)
return "ok"
}
// ReturnPoints returns to output points (ht, attack, mp...) formatted
// like in PokememBroBot itself.
func (p *Parsers) ReturnPoints(points int) string {
if points < 1000 {
return strconv.Itoa(points)
} else if points < 1000000 {
floatNum := float64(points) / 1000.0
return strconv.FormatFloat(floatNum, 'f', -1, 64) + "K"
} else {
floatNum := float64(points) / 1000000.0
return strconv.FormatFloat(floatNum, 'f', -1, 64) + "M"
}
}

View File

@ -0,0 +1,85 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package pokedexer
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
"strconv"
)
func (p *Pokedexer) pokememesListing(update *tgbotapi.Update, page int, pokememesArray []dbmapping.PokememeFull) {
message := "*Известные боту покемемы*\n"
message += "Список отсортирован по грейду и алфавиту.\n"
message += "Покедекс: " + strconv.Itoa(len(pokememesArray)) + " / 219\n"
message += "Отображаем покемемов с " + strconv.Itoa(((page-1)*50)+1) + " по " + strconv.Itoa(page*50) + "\n"
if len(pokememesArray) > page*50 {
message += "Переход на следующую страницу: /pokedeks" + strconv.Itoa(page+1)
}
if page > 1 {
message += "\nПереход на предыдущую страницу: /pokedeks" + strconv.Itoa(page-1)
}
message += "\n\n"
for i := range pokememesArray {
if (i+1 > 50*(page-1)) && (i+1 < (50*page)+1) {
pk := pokememesArray[i].Pokememe
pkE := pokememesArray[i].Elements
message += strconv.Itoa(i+1) + ". " + strconv.Itoa(pk.Grade)
message += "⃣ *" + pk.Name
message += "* (" + c.Statistics.GetPrintablePoints(pk.HP) + "-" + c.Statistics.GetPrintablePoints(pk.MP) + ") ⚔️ *"
message += c.Statistics.GetPrintablePoints(pk.Attack) + "* \\["
for j := range pkE {
message += pkE[j].Symbol
}
message += "] " + c.Statistics.GetPrintablePoints(pk.Price) + "$ /pk" + strconv.Itoa(pk.ID)
message += "\n"
}
}
if len(pokememesArray) > page*50 {
message += "\n"
message += "Переход на следующую страницу: /pokedeks" + strconv.Itoa(page+1)
}
if page > 1 {
message += "\nПереход на предыдущую страницу: /pokedeks" + strconv.Itoa(page-1)
}
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
}
func (p *Pokedexer) pokememeAddSuccessMessage(update *tgbotapi.Update) {
message := "*Покемем успешно добавлен.*\n\n"
message += "Посмотреть всех известных боту покемемов можно командой /pokedeks"
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
}
func (p *Pokedexer) pokememeAddDuplicateMessage(update *tgbotapi.Update) {
message := "*Мы уже знаем об этом покемеме*\n\n"
message += "Посмотреть всех известных боту покемемов можно командой /pokedeks\n\n"
message += "Если у покемема изменились описание или характеристики, напиши @fat0troll для обновления базы."
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
}
func (p *Pokedexer) pokememeAddFailureMessage(update *tgbotapi.Update) {
message := "*Неудачно получилось :(*\n\n"
message += "Случилась жуткая ошибка, и мы не смогли записать покемема в базу. Напиши @fat0troll, он разберется.\n\n"
message += "Посмотреть всех известных боту покемемов можно командой /pokedeks"
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
}

View File

@ -0,0 +1,21 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package pokedexerinterface
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
)
// PokedexerInterface implements Pokedexer for importing via appcontext.
type PokedexerInterface interface {
ParsePokememe(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
PokememesList(update *tgbotapi.Update)
PokememeInfo(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
BestPokememesList(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
GetPokememes() ([]dbmapping.PokememeFull, bool)
GetPokememeByID(pokememeID string) (dbmapping.PokememeFull, bool)
}

148
lib/pokedexer/responders.go Normal file
View File

@ -0,0 +1,148 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package pokedexer
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
"strconv"
"strings"
)
// BestPokememesList shows list for catching based on player league and grade
func (p *Pokedexer) BestPokememesList(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
pokememes, ok := p.getBestPokememes(playerRaw.ID)
if !ok {
c.Log.Error("Cannot get pokememes from getter!")
return "fail"
}
message := "*Лучшие покемемы для ловли*\n\n"
for i := range pokememes {
pk := pokememes[i].Pokememe
pkL := pokememes[i].Locations
pkE := pokememes[i].Elements
message += strconv.Itoa(pk.Grade) + "⃣ "
message += pk.Name + " (⚔"
message += c.Statistics.GetPrintablePoints(pk.Attack)
message += ", 🛡" + c.Statistics.GetPrintablePoints(pk.Defence) + ")"
for i := range pkE {
message += pkE[i].Symbol
}
message += " /pk" + strconv.Itoa(pk.ID) + "\n"
message += "Локации: "
for i := range pkL {
message += pkL[i].Symbol + pkL[i].Name
if i+1 < len(pkL) {
message += ", "
}
}
message += "\nКупить: "
if pk.Purchaseable {
message += "💲" + c.Statistics.GetPrintablePoints(pk.Price*3)
} else {
message += "Нельзя"
}
message += "\n\n"
}
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
return "ok"
}
// PokememesList lists all known pokememes
func (p *Pokedexer) PokememesList(update *tgbotapi.Update) {
pageNumber := strings.Replace(update.Message.Text, "/pokedex", "", 1)
pageNumber = strings.Replace(pageNumber, "/pokedeks", "", 1)
page, _ := strconv.Atoi(pageNumber)
if page == 0 {
page = 1
}
pokememesArray, ok := p.GetPokememes()
if !ok {
c.Talkers.BotError(update)
} else {
p.pokememesListing(update, page, pokememesArray)
}
}
// PokememeInfo shows information about single pokememe based on internal ID
func (p *Pokedexer) PokememeInfo(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
pokememeNumber := strings.Replace(update.Message.Text, "/pk", "", 1)
var calculatePossibilites = true
profileRaw, ok := c.Users.GetProfile(playerRaw.ID)
if !ok {
calculatePossibilites = false
}
pokememe, ok := p.GetPokememeByID(pokememeNumber)
if !ok {
return "fail"
}
pk := pokememe.Pokememe
message := strconv.Itoa(pk.Grade) + "⃣ *" + pk.Name + "*\n"
message += pk.Description + "\n\n"
message += "Элементы:"
for i := range pokememe.Elements {
message += " " + pokememe.Elements[i].Symbol
}
message += "\n⚔ Атака: *" + c.Statistics.GetPrintablePoints(pk.Attack)
message += "*\n❤ HP: *" + c.Statistics.GetPrintablePoints(pk.HP)
message += "*\n💙 MP: *" + c.Statistics.GetPrintablePoints(pk.MP)
if pk.Defence != pk.Attack {
message += "*\n🛡Защита: *" + c.Statistics.GetPrintablePoints(pk.Defence) + "* _(сопротивляемость покемема к поимке)_"
} else {
message += "*"
}
message += "\nСтоимость: *" + c.Statistics.GetPrintablePoints(pk.Price)
message += "*\nКупить: *"
if pk.Purchaseable {
message += "Можно"
} else {
message += "Нельзя"
}
message += "*\nОбитает:"
for i := range pokememe.Locations {
message += " *" + pokememe.Locations[i].Name + "*"
if (i + 1) < len(pokememe.Locations) {
message += ","
}
}
if calculatePossibilites {
if (pk.Grade < profileRaw.LevelID+2) && (pk.Grade > profileRaw.LevelID-3) {
message += "\nВероятность поимки:"
for i := range pokememe.Locations {
percentile, pokeballs := c.Statistics.PossibilityRequiredPokeballs(pokememe.Locations[i].ID, pk.Grade, profileRaw.LevelID)
message += "\n" + pokememe.Locations[i].Name + " "
message += strconv.FormatFloat(percentile, 'f', 2, 64) + "% или "
message += strconv.Itoa(pokeballs) + "⭕"
}
}
}
message += "\n" + pk.ImageURL
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
keyboard := tgbotapi.InlineKeyboardMarkup{}
for i := range pokememe.Locations {
var row []tgbotapi.InlineKeyboardButton
btn := tgbotapi.NewInlineKeyboardButtonSwitch(pokememe.Locations[i].Symbol+pokememe.Locations[i].Name, pokememe.Locations[i].Symbol+pokememe.Locations[i].Name)
row = append(row, btn)
keyboard.InlineKeyboard = append(keyboard.InlineKeyboard, row)
}
msg.ReplyMarkup = keyboard
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
return "ok"
}

View File

@ -22,7 +22,7 @@ func (r *Router) routeGroupRequest(update *tgbotapi.Update, playerRaw *dbmapping
if update.Message.NewChatMembers != nil {
newUsers := *update.Message.NewChatMembers
if len(newUsers) > 0 {
return c.Welcomer.WelcomeMessage(update)
return c.Welcomer.GroupWelcomeMessage(update)
}
}
// New chat names

View File

@ -33,51 +33,51 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi
switch {
case update.Message.Command() == "start":
if playerRaw.ID != 0 {
c.Talkers.HelloMessageAuthorized(update, playerRaw)
c.Welcomer.PrivateWelcomeMessageAuthorized(update, playerRaw)
return "ok"
}
c.Talkers.HelloMessageUnauthorized(update)
c.Welcomer.PrivateWelcomeMessageUnauthorized(update)
return "ok"
case update.Message.Command() == "help":
c.Talkers.HelpMessage(update, playerRaw)
return "ok"
// Pokememes info
case pokedexMsg.MatchString(text):
c.Talkers.PokememesList(update)
c.Pokedexer.PokememesList(update)
return "ok"
case pokememeInfoMsg.MatchString(text):
c.Talkers.PokememeInfo(update, playerRaw)
c.Pokedexer.PokememeInfo(update, playerRaw)
return "ok"
case update.Message.Command() == "me":
if playerRaw.ID != 0 {
c.Talkers.ProfileMessage(update, playerRaw)
c.Users.ProfileMessage(update, playerRaw)
return "ok"
}
c.Talkers.AnyMessageUnauthorized(update)
return "fail"
case update.Message.Command() == "best":
c.Talkers.BestPokememesList(update, playerRaw)
c.Pokedexer.BestPokememesList(update, playerRaw)
return "ok"
case update.Message.Command() == "send_all":
if c.Getters.PlayerBetterThan(playerRaw, "admin") {
c.Talkers.AdminBroadcastMessageCompose(update, playerRaw)
if c.Users.PlayerBetterThan(playerRaw, "admin") {
c.Broadcaster.AdminBroadcastMessageCompose(update, playerRaw)
return "ok"
}
c.Talkers.AnyMessageUnauthorized(update)
return "fail"
case update.Message.Command() == "send_confirm":
if c.Getters.PlayerBetterThan(playerRaw, "admin") {
c.Talkers.AdminBroadcastMessageSend(update, playerRaw)
if c.Users.PlayerBetterThan(playerRaw, "admin") {
c.Broadcaster.AdminBroadcastMessageSend(update, playerRaw)
return "ok"
}
c.Talkers.AnyMessageUnauthorized(update)
return "fail"
case update.Message.Command() == "group_chats":
if c.Getters.PlayerBetterThan(playerRaw, "admin") {
if c.Users.PlayerBetterThan(playerRaw, "admin") {
c.Chatter.GroupsList(update)
return "ok"
}
@ -85,7 +85,7 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi
c.Talkers.AnyMessageUnauthorized(update)
return "fail"
case update.Message.Command() == "squads":
if c.Getters.PlayerBetterThan(playerRaw, "admin") {
if c.Users.PlayerBetterThan(playerRaw, "admin") {
c.Squader.SquadsList(update)
return "ok"
}
@ -93,14 +93,14 @@ func (r *Router) routePrivateRequest(update *tgbotapi.Update, playerRaw *dbmappi
c.Talkers.AnyMessageUnauthorized(update)
return "fail"
case update.Message.Command() == "make_squad":
if c.Getters.PlayerBetterThan(playerRaw, "admin") {
if c.Users.PlayerBetterThan(playerRaw, "admin") {
return c.Squader.CreateSquad(update)
}
c.Talkers.AnyMessageUnauthorized(update)
return "fail"
case update.Message.Command() == "pin":
if c.Getters.PlayerBetterThan(playerRaw, "admin") {
if c.Users.PlayerBetterThan(playerRaw, "admin") {
return c.Pinner.PinMessageToAllChats(update)
}

View File

@ -9,7 +9,7 @@ import (
// RouteRequest decides, what to do with user input
func (r *Router) RouteRequest(update *tgbotapi.Update) string {
playerRaw, ok := c.Getters.GetOrCreatePlayer(update.Message.From.ID)
playerRaw, ok := c.Users.GetOrCreatePlayer(update.Message.From.ID)
if !ok {
// Silently fail
return "fail"

View File

@ -74,7 +74,7 @@ func (s *Squader) createSquad(update *tgbotapi.Update, chatID int, floodChatID i
if err != nil {
c.Log.Debug(err)
playerRaw, ok := c.Getters.GetOrCreatePlayer(update.Message.From.ID)
playerRaw, ok := c.Users.GetOrCreatePlayer(update.Message.From.ID)
if !ok {
return squad, "fail"
}
@ -240,8 +240,8 @@ func (s *Squader) SquadStatictics(squadID int) string {
for i := range squadMembers {
fullInfo := dbmapping.SquadPlayerFull{}
playerRaw, _ := c.Getters.GetPlayerByID(squadMembers[i].PlayerID)
profileRaw, _ := c.Getters.GetProfile(playerRaw.ID)
playerRaw, _ := c.Users.GetPlayerByID(squadMembers[i].PlayerID)
profileRaw, _ := c.Users.GetProfile(playerRaw.ID)
fullInfo.Squad = squad
fullInfo.Player = playerRaw

View File

@ -0,0 +1,28 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package statistics
import (
"lab.pztrn.name/fat0troll/i2_bot/lib/appcontext"
"lab.pztrn.name/fat0troll/i2_bot/lib/statistics/statisticsinterface"
)
var (
c *appcontext.Context
)
// Statistics is a function-handling struct for package statistics.
type Statistics struct{}
// New is an initialization function for appcontext
func New(ac *appcontext.Context) {
c = ac
s := &Statistics{}
c.RegisterStatisticsInterface(statisticsinterface.StatisticsInterface(s))
}
// Init is a initialization function for package
func (s *Statistics) Init() {
c.Log.Info("Initializing Statistics...")
}

40
lib/statistics/points.go Normal file
View File

@ -0,0 +1,40 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package statistics
import (
"strconv"
"strings"
)
// GetPoints returns points to use in database
func (s *Statistics) GetPoints(pointsStr string) int {
value := 0
if strings.HasSuffix(pointsStr, "K") {
valueNumber := strings.Replace(pointsStr, "K", "", 1)
valueFloat, _ := strconv.ParseFloat(valueNumber, 64)
value = int(valueFloat * 1000)
} else if strings.HasSuffix(pointsStr, "M") {
valueNumber := strings.Replace(pointsStr, "M", "", 1)
valueFloat, _ := strconv.ParseFloat(valueNumber, 64)
value = int(valueFloat * 1000000)
} else {
value, _ = strconv.Atoi(pointsStr)
}
return value
}
// GetPrintablePoints returns to output points (ht, attack, mp...) formatted
// like in PokememBroBot itself.
func (s *Statistics) GetPrintablePoints(points int) string {
if points < 1000 {
return strconv.Itoa(points)
} else if points < 1000000 {
floatNum := float64(points) / 1000.0
return strconv.FormatFloat(floatNum, 'f', -1, 64) + "K"
} else {
floatNum := float64(points) / 1000000.0
return strconv.FormatFloat(floatNum, 'f', -1, 64) + "M"
}
}

View File

@ -1,11 +1,11 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package getters
package statistics
// PossibilityRequiredPokeballs returns possibility of catching pokememe
// It's based on location, grade of pokememe and current level of player
func (g *Getters) PossibilityRequiredPokeballs(location int, grade int, lvl int) (float64, int) {
func (s *Statistics) PossibilityRequiredPokeballs(location int, grade int, lvl int) (float64, int) {
var basePossibility float64
var requiredPokeballs int
var percentile float64

View File

@ -0,0 +1,14 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package statisticsinterface
// StatisticsInterface implements Statistics for importing via appcontext.
type StatisticsInterface interface {
Init()
GetPoints(pointsStr string) int
GetPrintablePoints(points int) string
PossibilityRequiredPokeballs(location int, grade int, lvl int) (float64, int)
}

View File

@ -1,95 +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"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
"strconv"
"strings"
)
// AdminBroadcastMessageCompose saves message for future broadcast
func (t *Talkers) AdminBroadcastMessageCompose(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
broadcastingMessageBody := strings.Replace(update.Message.Text, "/send_all ", "", 1)
messageRaw, ok := c.Getters.CreateBroadcastMessage(playerRaw, broadcastingMessageBody, "all")
if !ok {
return "fail"
}
message := "Сообщение сохранено в базу.\n"
message += "Выглядеть оно будет так:"
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
broadcastingMessage := "*Привет, %username%!*\n\n"
broadcastingMessage += "*Важное сообщение от администратора " + update.Message.From.FirstName + " " + update.Message.From.LastName + "* (@" + update.Message.From.UserName + ")\n\n"
broadcastingMessage += messageRaw.Text
msg = tgbotapi.NewMessage(update.Message.Chat.ID, broadcastingMessage)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
message = "Чтобы отправить сообщение всем, отправь команду /send\\_confirm " + strconv.Itoa(messageRaw.ID)
msg = tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
return "ok"
}
// AdminBroadcastMessageSend sends saved message to all private chats
func (t *Talkers) AdminBroadcastMessageSend(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
messageNum := strings.Replace(update.Message.Text, "/send_confirm ", "", 1)
messageNumInt, _ := strconv.Atoi(messageNum)
messageRaw, ok := c.Getters.GetBroadcastMessageByID(messageNumInt)
if !ok {
return "fail"
}
if messageRaw.AuthorID != playerRaw.ID {
return "fail"
}
if messageRaw.Status != "new" {
return "fail"
}
broadcastingMessageBody := messageRaw.Text
privateChats, ok := c.Chatter.GetAllPrivateChats()
if !ok {
return "fail"
}
for i := range privateChats {
chat := privateChats[i]
broadcastingMessage := "*Привет, " + chat.Name + "!*\n\n"
broadcastingMessage += "*Важное сообщение от администратора " + update.Message.From.FirstName + " " + update.Message.From.LastName + "* (@" + update.Message.From.UserName + ")\n\n"
broadcastingMessage += broadcastingMessageBody
msg := tgbotapi.NewMessage(int64(chat.TelegramID), broadcastingMessage)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
}
messageRaw, ok = c.Getters.UpdateBroadcastMessageStatus(messageRaw.ID, "sent")
if !ok {
return "fail"
}
message := "Сообщение всем отправлено. Надеюсь, пользователи бота за него тебя не убьют.\n"
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
return "ok"
}

View File

@ -18,8 +18,8 @@ func (t *Talkers) AnyMessageUnauthorized(update *tgbotapi.Update) {
c.Bot.Send(msg)
}
// GetterError throws when bot can't get something
func (t *Talkers) GetterError(update *tgbotapi.Update) {
// BotError throws when bot can't do something
func (t *Talkers) BotError(update *tgbotapi.Update) {
message := "Ой, внутренняя ошибка в боте :(\n\n"
message += "Напиши @fat0troll, приложив форвардом последние сообщения до этого.\n"

View File

@ -24,5 +24,5 @@ func New(ac *appcontext.Context) {
// Init is an initialization function for talkers
func (t *Talkers) Init() {
c.Log.Info("Initializing responders...")
c.Log.Info("Initializing common Responders...")
}

View File

@ -17,7 +17,7 @@ func (t *Talkers) HelpMessage(update *tgbotapi.Update, playerRaw *dbmapping.Play
message += "+ /me посмотреть свой сохраненный профиль в боте\n"
message += "+ /best посмотреть лучших покемонов для поимки\n"
message += "+ /pokedeks получить список известных боту покемемов\n"
if c.Getters.PlayerBetterThan(playerRaw, "admin") {
if c.Users.PlayerBetterThan(playerRaw, "admin") {
message += "+ /send\\_all _текст_ — отправить сообщение всем пользователям бота\n"
message += "+ /group\\_chats — получить список групп, в которых работает бот.\n"
message += "+ /squads — получить список отрядов.\n"

View File

@ -1,151 +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"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
"strconv"
"strings"
)
// Internal functions
func (t *Talkers) pokememesListing(update *tgbotapi.Update, page int, pokememesArray []dbmapping.PokememeFull) {
message := "*Известные боту покемемы*\n"
message += "Список отсортирован по грейду и алфавиту.\n"
message += "Покедекс: " + strconv.Itoa(len(pokememesArray)) + " / 219\n"
message += "Отображаем покемемов с " + strconv.Itoa(((page-1)*50)+1) + " по " + strconv.Itoa(page*50) + "\n"
if len(pokememesArray) > page*50 {
message += "Переход на следующую страницу: /pokedeks" + strconv.Itoa(page+1)
}
if page > 1 {
message += "\nПереход на предыдущую страницу: /pokedeks" + strconv.Itoa(page-1)
}
message += "\n\n"
for i := range pokememesArray {
if (i+1 > 50*(page-1)) && (i+1 < (50*page)+1) {
pk := pokememesArray[i].Pokememe
pkE := pokememesArray[i].Elements
message += strconv.Itoa(i+1) + ". " + strconv.Itoa(pk.Grade)
message += "⃣ *" + pk.Name
message += "* (" + c.Parsers.ReturnPoints(pk.HP) + "-" + c.Parsers.ReturnPoints(pk.MP) + ") ⚔️ *"
message += c.Parsers.ReturnPoints(pk.Attack) + "* \\["
for j := range pkE {
message += pkE[j].Symbol
}
message += "] " + c.Parsers.ReturnPoints(pk.Price) + "$ /pk" + strconv.Itoa(pk.ID)
message += "\n"
}
}
if len(pokememesArray) > page*50 {
message += "\n"
message += "Переход на следующую страницу: /pokedeks" + strconv.Itoa(page+1)
}
if page > 1 {
message += "\nПереход на предыдущую страницу: /pokedeks" + strconv.Itoa(page-1)
}
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
}
// External functions
// PokememesList lists all known pokememes
func (t *Talkers) PokememesList(update *tgbotapi.Update) {
pageNumber := strings.Replace(update.Message.Text, "/pokedex", "", 1)
pageNumber = strings.Replace(pageNumber, "/pokedeks", "", 1)
page, _ := strconv.Atoi(pageNumber)
if page == 0 {
page = 1
}
pokememesArray, ok := c.Getters.GetPokememes()
if !ok {
t.GetterError(update)
} else {
t.pokememesListing(update, page, pokememesArray)
}
}
// PokememeInfo shows information about single pokememe based on internal ID
func (t *Talkers) PokememeInfo(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
pokememeNumber := strings.Replace(update.Message.Text, "/pk", "", 1)
var calculatePossibilites = true
profileRaw, ok := c.Getters.GetProfile(playerRaw.ID)
if !ok {
calculatePossibilites = false
}
pokememe, ok := c.Getters.GetPokememeByID(pokememeNumber)
if !ok {
return "fail"
}
pk := pokememe.Pokememe
message := strconv.Itoa(pk.Grade) + "⃣ *" + pk.Name + "*\n"
message += pk.Description + "\n\n"
message += "Элементы:"
for i := range pokememe.Elements {
message += " " + pokememe.Elements[i].Symbol
}
message += "\n⚔ Атака: *" + c.Parsers.ReturnPoints(pk.Attack)
message += "*\n❤ HP: *" + c.Parsers.ReturnPoints(pk.HP)
message += "*\n💙 MP: *" + c.Parsers.ReturnPoints(pk.MP)
if pk.Defence != pk.Attack {
message += "*\n🛡Защита: *" + c.Parsers.ReturnPoints(pk.Defence) + "* _(сопротивляемость покемема к поимке)_"
} else {
message += "*"
}
message += "\nСтоимость: *" + c.Parsers.ReturnPoints(pk.Price)
message += "*\nКупить: *"
if pk.Purchaseable {
message += "Можно"
} else {
message += "Нельзя"
}
message += "*\nОбитает:"
for i := range pokememe.Locations {
message += " *" + pokememe.Locations[i].Name + "*"
if (i + 1) < len(pokememe.Locations) {
message += ","
}
}
if calculatePossibilites {
if (pk.Grade < profileRaw.LevelID+2) && (pk.Grade > profileRaw.LevelID-3) {
message += "\nВероятность поимки:"
for i := range pokememe.Locations {
percentile, pokeballs := c.Getters.PossibilityRequiredPokeballs(pokememe.Locations[i].ID, pk.Grade, profileRaw.LevelID)
message += "\n" + pokememe.Locations[i].Name + " "
message += strconv.FormatFloat(percentile, 'f', 2, 64) + "% или "
message += strconv.Itoa(pokeballs) + "⭕"
}
}
}
message += "\n" + pk.ImageURL
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
keyboard := tgbotapi.InlineKeyboardMarkup{}
for i := range pokememe.Locations {
var row []tgbotapi.InlineKeyboardButton
btn := tgbotapi.NewInlineKeyboardButtonSwitch(pokememe.Locations[i].Symbol+pokememe.Locations[i].Name, pokememe.Locations[i].Symbol+pokememe.Locations[i].Name)
row = append(row, btn)
keyboard.InlineKeyboard = append(keyboard.InlineKeyboard, row)
}
msg.ReplyMarkup = keyboard
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
return "ok"
}

View File

@ -1,43 +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"
)
// PokememeAddSuccessMessage shows pokememe adding success message
func (t *Talkers) PokememeAddSuccessMessage(update *tgbotapi.Update) {
message := "*Покемем успешно добавлен.*\n\n"
message += "Посмотреть всех известных боту покемемов можно командой /pokedeks"
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
}
// PokememeAddDuplicateMessage shows pokememe add duplication message
func (t *Talkers) PokememeAddDuplicateMessage(update *tgbotapi.Update) {
message := "*Мы уже знаем об этом покемеме*\n\n"
message += "Посмотреть всех известных боту покемемов можно командой /pokedeks\n\n"
message += "Если у покемема изменились описание или характеристики, напиши @fat0troll для обновления базы."
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
}
// PokememeAddFailureMessage shows pokememe add error message
func (t *Talkers) PokememeAddFailureMessage(update *tgbotapi.Update) {
message := "*Неудачно получилось :(*\n\n"
message += "Случилась жуткая ошибка, и мы не смогли записать покемема в базу. Напиши @fat0troll, он разберется.\n\n"
message += "Посмотреть всех известных боту покемемов можно командой /pokedeks"
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
}

View File

@ -1,55 +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"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
"strconv"
)
// BestPokememesList shows list for catching based on player league and grade
func (t *Talkers) BestPokememesList(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
pokememes, ok := c.Getters.GetBestPokememes(playerRaw.ID)
if !ok {
c.Log.Error("Cannot get pokememes from getter!")
return "fail"
}
message := "*Лучшие покемемы для ловли*\n\n"
for i := range pokememes {
pk := pokememes[i].Pokememe
pkL := pokememes[i].Locations
pkE := pokememes[i].Elements
message += strconv.Itoa(pk.Grade) + "⃣ "
message += pk.Name + " (⚔"
message += c.Parsers.ReturnPoints(pk.Attack)
message += ", 🛡" + c.Parsers.ReturnPoints(pk.Defence) + ")"
for i := range pkE {
message += pkE[i].Symbol
}
message += " /pk" + strconv.Itoa(pk.ID) + "\n"
message += "Локации: "
for i := range pkL {
message += pkL[i].Symbol + pkL[i].Name
if i+1 < len(pkL) {
message += ", "
}
}
message += "\nКупить: "
if pk.Purchaseable {
message += "💲" + c.Parsers.ReturnPoints(pk.Price*3)
} else {
message += "Нельзя"
}
message += "\n\n"
}
msg := tgbotapi.NewMessage(update.Message.Chat.ID, message)
msg.ParseMode = "Markdown"
c.Bot.Send(msg)
return "ok"
}

View File

@ -11,25 +11,10 @@ import (
// TalkersInterface implements Talkers for importing via appcontex
type TalkersInterface interface {
Init()
HelloMessageUnauthorized(update *tgbotapi.Update)
HelloMessageAuthorized(update *tgbotapi.Update, playerRaw *dbmapping.Player)
HelpMessage(update *tgbotapi.Update, playerRaw *dbmapping.Player)
PokememesList(update *tgbotapi.Update)
PokememeInfo(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
BestPokememesList(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
PokememeAddSuccessMessage(update *tgbotapi.Update)
PokememeAddDuplicateMessage(update *tgbotapi.Update)
PokememeAddFailureMessage(update *tgbotapi.Update)
ProfileAddSuccessMessage(update *tgbotapi.Update)
ProfileAddFailureMessage(update *tgbotapi.Update)
ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
AnyMessageUnauthorized(update *tgbotapi.Update)
GetterError(update *tgbotapi.Update)
AdminBroadcastMessageCompose(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
AdminBroadcastMessageSend(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
BotError(update *tgbotapi.Update)
DurakMessage(update *tgbotapi.Update)
MatMessage(update *tgbotapi.Update)

28
lib/users/exported.go Normal file
View File

@ -0,0 +1,28 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package users
import (
"lab.pztrn.name/fat0troll/i2_bot/lib/appcontext"
"lab.pztrn.name/fat0troll/i2_bot/lib/users/usersinterface"
)
var (
c *appcontext.Context
)
// Users is a function-handling struct for users
type Users struct{}
// New is a appcontext initialization function
func New(ac *appcontext.Context) {
c = ac
u := &Users{}
c.RegisterUsersInterface(usersinterface.UsersInterface(u))
}
// Init is an initialization function for users
func (u *Users) Init() {
c.Log.Info("Initializing Users...")
}

View File

@ -1,15 +1,27 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package getters
package users
import (
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
"time"
)
// GetProfile returns last saved profile of player
func (u *Users) GetProfile(playerID int) (dbmapping.Profile, bool) {
profileRaw := dbmapping.Profile{}
err := c.Db.Get(&profileRaw, c.Db.Rebind("SELECT * FROM profiles WHERE player_id=? ORDER BY created_at DESC LIMIT 1"), playerID)
if err != nil {
c.Log.Error(err)
return profileRaw, false
}
return profileRaw, true
}
// GetPlayerByID returns dbmapping.Player instance with given ID.
func (g *Getters) GetPlayerByID(playerID int) (dbmapping.Player, bool) {
func (u *Users) GetPlayerByID(playerID int) (dbmapping.Player, bool) {
playerRaw := dbmapping.Player{}
err := c.Db.Get(&playerRaw, c.Db.Rebind("SELECT * FROM players WHERE id=?"), playerID)
if err != nil {
@ -22,7 +34,7 @@ func (g *Getters) GetPlayerByID(playerID int) (dbmapping.Player, bool) {
// GetOrCreatePlayer seeks for player in database via Telegram ID.
// In case, when there is no player with such ID, new player will be created.
func (g *Getters) GetOrCreatePlayer(telegramID int) (dbmapping.Player, bool) {
func (u *Users) GetOrCreatePlayer(telegramID int) (dbmapping.Player, bool) {
playerRaw := dbmapping.Player{}
err := c.Db.Get(&playerRaw, c.Db.Rebind("SELECT * FROM players WHERE telegram_id=?"), telegramID)
if err != nil {
@ -49,7 +61,7 @@ func (g *Getters) GetOrCreatePlayer(telegramID int) (dbmapping.Player, bool) {
// PlayerBetterThan return true, if profile is more or equal powerful than
// provided power level
func (g *Getters) PlayerBetterThan(playerRaw *dbmapping.Player, powerLevel string) bool {
func (u *Users) PlayerBetterThan(playerRaw *dbmapping.Player, powerLevel string) bool {
var isBetter = false
switch playerRaw.Status {
case "owner":

View File

@ -1,7 +1,7 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package parsers
package users
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
@ -14,13 +14,13 @@ import (
// Internal functions
func (p *Parsers) fillProfilePokememe(profileID int, meme string, attack string, rarity string) {
func (u *Users) fillProfilePokememe(profileID int, meme string, attack string, rarity string) {
spkRaw := dbmapping.Pokememe{}
err := c.Db.Get(&spkRaw, c.Db.Rebind("SELECT * FROM pokememes WHERE name='"+meme+"';"))
if err != nil {
c.Log.Error(err.Error())
} else {
attackInt := p.getPoints(attack)
attackInt := c.Statistics.GetPoints(attack)
ppk := dbmapping.ProfilePokememe{}
ppk.ProfileID = profileID
ppk.PokememeID = spkRaw.ID
@ -37,7 +37,7 @@ func (p *Parsers) fillProfilePokememe(profileID int, meme string, attack string,
// External functions
// ParseProfile parses user profile, forwarded from PokememBroBot, to database
func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
func (u *Users) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
text := update.Message.Text
c.Log.Info(text)
@ -78,6 +78,7 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
err1 := c.Db.Get(&league, c.Db.Rebind("SELECT * FROM leagues WHERE symbol='"+string(currentRunes[0])+"'"))
if err1 != nil {
c.Log.Error(err1.Error())
u.profileAddFailureMessage(update)
return "fail"
}
for j := range currentRunes {
@ -91,6 +92,7 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
levelArray := levelRx.FindAllString(currentString, -1)
if len(levelArray) < 1 {
c.Log.Error("Level string broken")
u.profileAddFailureMessage(update)
return "fail"
}
level = levelArray[0]
@ -102,6 +104,7 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
expArray := expRx.FindAllString(currentString, -1)
if len(expArray) < 4 {
c.Log.Error("Exp string broken")
u.profileAddFailureMessage(update)
return "fail"
}
exp = expArray[0]
@ -115,6 +118,7 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
pkbArray := pkbRx.FindAllString(currentString, -1)
if len(pkbArray) < 2 {
c.Log.Error("Pokeballs string broken")
u.profileAddFailureMessage(update)
return "fail"
}
pokeballs = pkbArray[1]
@ -126,12 +130,13 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
wealthArray := wealthRx.FindAllString(currentString, -1)
if len(wealthArray) < 2 {
c.Log.Error("Wealth string broken")
u.profileAddFailureMessage(update)
return "fail"
}
wealth = wealthArray[0]
wealthInt = p.getPoints(wealth)
wealthInt = c.Statistics.GetPoints(wealth)
crystalls = wealthArray[1]
crystallsInt = p.getPoints(crystalls)
crystallsInt = c.Statistics.GetPoints(crystalls)
}
if strings.HasPrefix(currentString, "🔫") {
@ -146,11 +151,12 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
pkNumArray := pkmnumRx.FindAllString(currentString, -1)
if len(pkNumArray) < 3 {
c.Log.Error("Pokememes count broken")
u.profileAddFailureMessage(update)
return "fail"
}
pokememesCount, _ := strconv.Atoi(pkNumArray[0])
pokememesWealth = pkNumArray[2]
pokememesWealthInt = p.getPoints(pokememesWealth)
pokememesWealthInt = c.Statistics.GetPoints(pokememesWealth)
if pokememesCount > 0 {
for pi := 0; pi < pokememesCount; pi++ {
pokememeString := string(profileRunesArray[i+1+pi])
@ -162,7 +168,7 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
pkName = strings.TrimSuffix(pkName, " ")
pkName = strings.Split(pkName, "⃣ ")[1]
pokememes[pkName] = pkAttack
powerInt += p.getPoints(pkAttack)
powerInt += c.Statistics.GetPoints(pkAttack)
}
}
}
@ -210,6 +216,7 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
_, err4 := c.Db.NamedExec("UPDATE `players` SET league_id=:league_id, status=:status WHERE id=:id", &playerRaw)
if err4 != nil {
c.Log.Error(err4.Error())
u.profileAddFailureMessage(update)
return "fail"
}
} else if playerRaw.LeagueID != league.ID {
@ -220,11 +227,13 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
_, err5 := c.Db.NamedExec("INSERT INTO players VALUES(NULL, :telegram_id, :league_id, :status, :created_at, :updated_at)", &playerRaw)
if err5 != nil {
c.Log.Error(err5.Error())
u.profileAddFailureMessage(update)
return "fail"
}
err6 := c.Db.Get(&playerRaw, c.Db.Rebind("SELECT * FROM players WHERE telegram_id='"+strconv.Itoa(playerRaw.TelegramID)+"' AND league_id='"+strconv.Itoa(league.ID)+"';"))
if err6 != nil {
c.Log.Error(err6.Error())
u.profileAddFailureMessage(update)
return "fail"
}
}
@ -247,6 +256,7 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
_, err3 := c.Db.NamedExec("INSERT INTO `profiles` VALUES(NULL, :player_id, :nickname, :telegram_nickname, :level_id, :pokeballs, :wealth, :pokememes_wealth, :exp, :egg_exp, :power, :weapon_id, :crystalls, :created_at)", &profileRaw)
if err3 != nil {
c.Log.Error(err3.Error())
u.profileAddFailureMessage(update)
return "fail"
}
@ -254,6 +264,7 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
if err8 != nil {
c.Log.Error(err8.Error())
c.Log.Error("Profile isn't added!")
u.profileAddFailureMessage(update)
return "fail"
}
@ -261,6 +272,7 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
_, err7 := c.Db.NamedExec("UPDATE `players` SET updated_at=:updated_at WHERE id=:id", &playerRaw)
if err7 != nil {
c.Log.Error(err7.Error())
u.profileAddFailureMessage(update)
return "fail"
}
@ -282,8 +294,9 @@ func (p *Parsers) ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Pla
rarity = "super liber"
meme = strings.Replace(meme, "🔷", "", 1)
}
p.fillProfilePokememe(profileRaw.ID, meme, attack, rarity)
u.fillProfilePokememe(profileRaw.ID, meme, attack, rarity)
}
u.profileAddSuccessMessage(update)
return "ok"
}

View File

@ -1,7 +1,7 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package talkers
package users
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
@ -10,8 +10,8 @@ import (
)
// ProfileMessage shows current player's profile
func (t *Talkers) ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
profileRaw, ok := c.Getters.GetProfile(playerRaw.ID)
func (u *Users) ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.Player) string {
profileRaw, ok := u.GetProfile(playerRaw.ID)
if !ok {
c.Talkers.AnyMessageUnauthorized(update)
return "fail"
@ -60,13 +60,13 @@ func (t *Talkers) ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.P
message += "\n👤 " + strconv.Itoa(profileRaw.LevelID)
message += " | 🎓 " + strconv.Itoa(profileRaw.Exp) + "/" + strconv.Itoa(level.MaxExp)
message += " | 🥚 " + strconv.Itoa(profileRaw.EggExp) + "/" + strconv.Itoa(level.MaxEgg)
message += "\n💲" + c.Parsers.ReturnPoints(profileRaw.Wealth)
message += "\n💲" + c.Statistics.GetPrintablePoints(profileRaw.Wealth)
message += " |💎" + strconv.Itoa(profileRaw.Crystalls)
message += " |⭕" + strconv.Itoa(profileRaw.Pokeballs)
message += "\n⚔Атака: 1 + " + c.Parsers.ReturnPoints(weapon.Power) + " + " + c.Parsers.ReturnPoints(attackPokememes) + "\n"
message += "\n⚔Атака: 1 + " + c.Statistics.GetPrintablePoints(weapon.Power) + " + " + c.Statistics.GetPrintablePoints(attackPokememes) + "\n"
if profileRaw.WeaponID != 0 {
message += "\n🔫Оружие: " + weapon.Name + " " + c.Parsers.ReturnPoints(weapon.Power) + "⚔"
message += "\n🔫Оружие: " + weapon.Name + " " + c.Statistics.GetPrintablePoints(weapon.Power) + "⚔"
}
message += "\n🐱Покемемы:"
@ -75,11 +75,11 @@ func (t *Talkers) ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.P
if profilePokememes[i].PokememeID == pokememes[j].ID {
message += "\n" + strconv.Itoa(pokememes[j].Grade)
message += "⃣ " + pokememes[j].Name
message += " +" + c.Parsers.ReturnPoints(profilePokememes[i].PokememeAttack) + "⚔"
message += " +" + c.Statistics.GetPrintablePoints(profilePokememes[i].PokememeAttack) + "⚔"
}
}
}
message += "\nСтоимость покемемов на руках: " + c.Parsers.ReturnPoints(profileRaw.PokememesWealth) + "$"
message += "\nСтоимость покемемов на руках: " + c.Statistics.GetPrintablePoints(profileRaw.PokememesWealth) + "$"
message += "\n\n💳" + strconv.Itoa(playerRaw.TelegramID)
message += "\n⏰Последнее обновление профиля: " + profileRaw.CreatedAt.Format("02.01.2006 15:04:05")
message += "\n\nНе забывай обновляться, это важно для получения актуальной информации.\n\n"

View File

@ -1,14 +1,16 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package talkers
package users
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
)
// ProfileAddSuccessMessage shows profile addition success message
func (t *Talkers) ProfileAddSuccessMessage(update *tgbotapi.Update) {
// Internal functions for Users package
// profileAddSuccessMessage shows profile addition success message
func (u *Users) profileAddSuccessMessage(update *tgbotapi.Update) {
message := "*Профиль успешно обновлен.*\n\n"
message += "Функциональность бота держится на актуальности профилей. Обновляйся почаще, и да пребудет с тобой Рандом!\n"
message += "Сохраненный профиль ты можешь просмотреть командой /me.\n\n"
@ -20,8 +22,8 @@ func (t *Talkers) ProfileAddSuccessMessage(update *tgbotapi.Update) {
c.Bot.Send(msg)
}
// ProfileAddFailureMessage shows profile addition failure message
func (t *Talkers) ProfileAddFailureMessage(update *tgbotapi.Update) {
// profileAddFailureMessage shows profile addition failure message
func (u *Users) profileAddFailureMessage(update *tgbotapi.Update) {
message := "*Неудачно получилось :(*\n\n"
message += "Случилась жуткая ошибка, и мы не смогли записать профиль в базу. Напиши @fat0troll, он разберется."

View File

@ -0,0 +1,23 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package usersinterface
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
)
// UsersInterface implements Users for importing via appcontex
type UsersInterface interface {
Init()
ParseProfile(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
GetProfile(playerID int) (dbmapping.Profile, bool)
GetOrCreatePlayer(telegramID int) (dbmapping.Player, bool)
GetPlayerByID(playerID int) (dbmapping.Player, bool)
PlayerBetterThan(playerRaw *dbmapping.Player, powerLevel string) bool
ProfileMessage(update *tgbotapi.Update, playerRaw *dbmapping.Player) string
}

View File

@ -1,15 +1,15 @@
// i2_bot Instinct PokememBro Bot
// Copyright (c) 2017 Vladimir "fat0troll" Hodakov
package talkers
package welcomer
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
)
// HelloMessageUnauthorized tell new user what to do.
func (t *Talkers) HelloMessageUnauthorized(update *tgbotapi.Update) {
// PrivateWelcomeMessageUnauthorized tell new user what to do.
func (w *Welcomer) PrivateWelcomeMessageUnauthorized(update *tgbotapi.Update) {
message := "*Бот Инстинкта приветствует тебя!*\n\n"
message += "Для начала работы с ботом, пожалуйста, перешли от бота игры @PokememBroBot профиль героя.\n"
message += "Все дальнейшие действия с ботом возможны лишь при наличии профиля игрока."
@ -20,8 +20,8 @@ func (t *Talkers) HelloMessageUnauthorized(update *tgbotapi.Update) {
c.Bot.Send(msg)
}
// HelloMessageAuthorized greets existing user
func (t *Talkers) HelloMessageAuthorized(update *tgbotapi.Update, playerRaw *dbmapping.Player) {
// PrivateWelcomeMessageAuthorized greets existing user
func (w *Welcomer) PrivateWelcomeMessageAuthorized(update *tgbotapi.Update, playerRaw *dbmapping.Player) {
message := "*Бот Инстинкта приветствует тебя. Снова.*\n\n"
message += "Привет, " + update.Message.From.FirstName + " " + update.Message.From.LastName + "!\n"
message += "Последнее обновление информации о тебе: " + playerRaw.UpdatedAt.Format("02.01.2006 15:04:05 -0700")
@ -31,3 +31,18 @@ func (t *Talkers) HelloMessageAuthorized(update *tgbotapi.Update, playerRaw *dbm
c.Bot.Send(msg)
}
// GroupWelcomeMessage welcomes new user on group or bot itself
func (w *Welcomer) GroupWelcomeMessage(update *tgbotapi.Update) string {
newUsers := *update.Message.NewChatMembers
for i := range newUsers {
if (newUsers[i].UserName == "i2_bot") || (newUsers[i].UserName == "i2_dev_bot") {
w.groupStartMessage(update)
}
newUser := newUsers[i]
w.groupWelcomeUser(update, &newUser)
}
return "ok"
}

View File

@ -9,12 +9,12 @@ import (
)
func (w *Welcomer) groupWelcomeUser(update *tgbotapi.Update, newUser *tgbotapi.User) string {
playerRaw, ok := c.Getters.GetOrCreatePlayer(newUser.ID)
playerRaw, ok := c.Users.GetOrCreatePlayer(newUser.ID)
if !ok {
return "fail"
}
profileRaw, profileExist := c.Getters.GetProfile(playerRaw.ID)
profileRaw, profileExist := c.Users.GetProfile(playerRaw.ID)
message := "*Бот Инстинкта приветствует тебя, *@"
message += newUser.UserName
@ -54,19 +54,4 @@ func (w *Welcomer) groupStartMessage(update *tgbotapi.Update) string {
c.Bot.Send(msg)
return "ok"
}
// WelcomeMessage welcomes new user on group or bot itself
func (w *Welcomer) WelcomeMessage(update *tgbotapi.Update) string {
newUsers := *update.Message.NewChatMembers
for i := range newUsers {
if (newUsers[i].UserName == "i2_bot") || (newUsers[i].UserName == "i2_dev_bot") {
w.groupStartMessage(update)
}
newUser := newUsers[i]
w.groupWelcomeUser(update, &newUser)
}
return "ok"
}
}

View File

@ -5,10 +5,14 @@ package welcomerinterface
import (
"github.com/go-telegram-bot-api/telegram-bot-api"
"lab.pztrn.name/fat0troll/i2_bot/lib/dbmapping"
)
// WelcomerInterface implements Welcomer for importing via appcontex
type WelcomerInterface interface {
Init()
WelcomeMessage(update *tgbotapi.Update) string
PrivateWelcomeMessageUnauthorized(update *tgbotapi.Update)
PrivateWelcomeMessageAuthorized(update *tgbotapi.Update, playerRaw *dbmapping.Player)
GroupWelcomeMessage(update *tgbotapi.Update) string
}