From fe496d696fb5425244ae539e5de51c88879985f0 Mon Sep 17 00:00:00 2001 From: Vladimir Hodakov Date: Fri, 6 Oct 2017 02:56:06 +0400 Subject: [PATCH] Database connections, refactoring, pokememe parsing in progress --- README | 3 + i2_bot.go | 7 +- lib/appcontext/appcontext.go | 18 ++++ lib/dbmappings/elements.go | 17 ++++ lib/dbmappings/leagues.go | 16 ++++ lib/dbmappings/locations.go | 16 ++++ lib/dbmappings/players.go | 19 ++++ lib/dbmappings/pokememes.go | 25 ++++++ lib/dbmappings/pokememes_elements.go | 16 ++++ lib/dbmappings/pokememes_locations.go | 16 ++++ lib/dbmappings/profiles.go | 23 +++++ lib/migrations/1_hello.go | 18 ++++ lib/migrations/2_create_players.go | 38 ++++++++ lib/migrations/3_create_profiles.go | 42 +++++++++ lib/migrations/4_create_pokememes.go | 44 ++++++++++ lib/migrations/5_create_locations.go | 61 +++++++++++++ lib/migrations/6_create_elements.go | 86 +++++++++++++++++++ lib/migrations/7_create_leagues.go | 49 +++++++++++ lib/migrations/8_create_relations.go | 52 +++++++++++ lib/migrations/exported.go | 20 +++++ lib/migrations/migrations.go | 42 +++++++++ .../migrationsinterface.go | 10 +++ lib/parsers/exported.go | 22 +++++ .../parsersinterface/parsersinterface.go | 14 +++ lib/parsers/pokememe.go | 57 ++++++++++++ lib/router/router.go | 76 ++++++++++++---- lib/talkers/errors.go | 19 ++++ lib/talkers/hello.go | 32 +++++++ lib/talkers/help.go | 2 +- 29 files changed, 842 insertions(+), 18 deletions(-) create mode 100644 README create mode 100644 lib/dbmappings/elements.go create mode 100644 lib/dbmappings/leagues.go create mode 100644 lib/dbmappings/locations.go create mode 100644 lib/dbmappings/players.go create mode 100644 lib/dbmappings/pokememes.go create mode 100644 lib/dbmappings/pokememes_elements.go create mode 100644 lib/dbmappings/pokememes_locations.go create mode 100644 lib/dbmappings/profiles.go create mode 100644 lib/migrations/1_hello.go create mode 100644 lib/migrations/2_create_players.go create mode 100644 lib/migrations/3_create_profiles.go create mode 100644 lib/migrations/4_create_pokememes.go create mode 100644 lib/migrations/5_create_locations.go create mode 100644 lib/migrations/6_create_elements.go create mode 100644 lib/migrations/7_create_leagues.go create mode 100644 lib/migrations/8_create_relations.go create mode 100644 lib/migrations/exported.go create mode 100644 lib/migrations/migrations.go create mode 100644 lib/migrations/migrationsinterface/migrationsinterface.go create mode 100644 lib/parsers/exported.go create mode 100644 lib/parsers/parsersinterface/parsersinterface.go create mode 100644 lib/parsers/pokememe.go create mode 100644 lib/talkers/errors.go create mode 100644 lib/talkers/hello.go diff --git a/README b/README new file mode 100644 index 0000000..dc11bf0 --- /dev/null +++ b/README @@ -0,0 +1,3 @@ +#### i2_bot: бот лиги Инстинкт игры @PokememBroBot + +Миграции базы данных рулит гусь (``goose``). diff --git a/i2_bot.go b/i2_bot.go index 9287a2c..cdc8f20 100644 --- a/i2_bot.go +++ b/i2_bot.go @@ -10,6 +10,8 @@ import ( "gopkg.in/telegram-bot-api.v4" // local "./lib/appcontext" + "./lib/migrations" + "./lib/parsers" "./lib/router" ) @@ -21,6 +23,9 @@ func main() { c := appcontext.New() c.Init() router.New(c) + migrations.New(c) + c.RunDatabaseMigrations() + parsers.New(c) u := tgbotapi.NewUpdate(0) u.Timeout = 60 @@ -28,7 +33,7 @@ func main() { updates, _ := c.Bot.GetUpdatesChan(u) for update := range updates { - if update.Message == nil { + if update.Message == nil || update.Message.From == nil { continue } else if update.Message.Date < (int(time.Now().Unix()) - 1) { // Ignore old messages diff --git a/lib/appcontext/appcontext.go b/lib/appcontext/appcontext.go index 93d23c1..9f413f9 100644 --- a/lib/appcontext/appcontext.go +++ b/lib/appcontext/appcontext.go @@ -11,13 +11,17 @@ import ( "../config" "../connections" // interfaces + "../migrations/migrationsinterface" + "../parsers/parsersinterface" "../router/routerinterface" ) type Context struct { Cfg *config.Config Bot *tgbotapi.BotAPI + Migrations migrationsinterface.MigrationsInterface Router routerinterface.RouterInterface + Parsers parsersinterface.ParsersInterface Db *sqlx.DB } @@ -32,3 +36,17 @@ func (c *Context) RegisterRouterInterface(ri routerinterface.RouterInterface) { c.Router = ri c.Router.Init() } + +func (c *Context) RegisterMigrationsInterface(mi migrationsinterface.MigrationsInterface) { + c.Migrations = mi + c.Migrations.Init() +} + +func (c *Context) RegisterParsersInterface(pi parsersinterface.ParsersInterface) { + c.Parsers = pi +} + +func (c *Context) RunDatabaseMigrations() { + c.Migrations.SetDialect("mysql") + c.Migrations.Migrate() +} diff --git a/lib/dbmappings/elements.go b/lib/dbmappings/elements.go new file mode 100644 index 0000000..c0ee84d --- /dev/null +++ b/lib/dbmappings/elements.go @@ -0,0 +1,17 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmappings + +import ( + // stdlib + "time" +) + +type Elements struct { + Id int `db:"id"` + Symbol string `db:"symbol"` + Name string `db:"name"` + League_id int `db:"league_id"` + Created_at *time.Time `db:"created_at"` +} diff --git a/lib/dbmappings/leagues.go b/lib/dbmappings/leagues.go new file mode 100644 index 0000000..c959a34 --- /dev/null +++ b/lib/dbmappings/leagues.go @@ -0,0 +1,16 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmappings + +import ( + // stdlib + "time" +) + +type Leagues struct { + Id int `db:"id"` + Symbol string `db:"symbol"` + Name string `db:"league_id"` + Created_at *time.Time `db:"created_at"` +} diff --git a/lib/dbmappings/locations.go b/lib/dbmappings/locations.go new file mode 100644 index 0000000..4ebff50 --- /dev/null +++ b/lib/dbmappings/locations.go @@ -0,0 +1,16 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmappings + +import ( + // stdlib + "time" +) + +type Locations struct { + Id int `db:"id"` + Symbol string `db:"symbol"` + Name string `db:"league_id"` + Created_at *time.Time `db:"created_at"` +} diff --git a/lib/dbmappings/players.go b/lib/dbmappings/players.go new file mode 100644 index 0000000..aa01d69 --- /dev/null +++ b/lib/dbmappings/players.go @@ -0,0 +1,19 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmappings + +import ( + // stdlib + "time" +) + +type Players struct { + Id int `db:"id"` + Telegram_id int `db:"telegram_id"` + League_id int `db:"league_id"` + Squad_id int `db:"squad_id"` + Status string `db:"status"` + Created_at *time.Time `db:"created_at"` + Updated_at *time.Time `db:"updated_at"` +} diff --git a/lib/dbmappings/pokememes.go b/lib/dbmappings/pokememes.go new file mode 100644 index 0000000..e496274 --- /dev/null +++ b/lib/dbmappings/pokememes.go @@ -0,0 +1,25 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmappings + +import ( + // stdlib + "time" +) + +type Pokememes struct { + Id int `db:"id"` + Grade int `db:"grade"` + Name string `db:"league_id"` + Description string `db:"description"` + Attack int `db:"attack"` + HP int `db:"int"` + MP int `db:"mp"` + Defence int `db:"defence"` + Price int `db:"price"` + Purchaseable bool `db:"purchaseable"` + Image_url string `db:"image_url"` + Player_id int `db:"player_id"` + Created_at *time.Time `db:"created_at"` +} diff --git a/lib/dbmappings/pokememes_elements.go b/lib/dbmappings/pokememes_elements.go new file mode 100644 index 0000000..5baf1c8 --- /dev/null +++ b/lib/dbmappings/pokememes_elements.go @@ -0,0 +1,16 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmappings + +import ( + // stdlib + "time" +) + +type PokememesElements struct { + Id int `db:"id"` + Pokememe_id int `db:"pokememe_id"` + Element_id int `db:"element_id"` + Created_at *time.Time `db:"created_at"` +} diff --git a/lib/dbmappings/pokememes_locations.go b/lib/dbmappings/pokememes_locations.go new file mode 100644 index 0000000..1ae6df2 --- /dev/null +++ b/lib/dbmappings/pokememes_locations.go @@ -0,0 +1,16 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmappings + +import ( + // stdlib + "time" +) + +type PokememesLocations struct { + Id int `db:"id"` + Pokememe_id int `db:"pokememe_id"` + Location_id int `db:"location_id"` + Created_at *time.Time `db:"created_at"` +} diff --git a/lib/dbmappings/profiles.go b/lib/dbmappings/profiles.go new file mode 100644 index 0000000..2213977 --- /dev/null +++ b/lib/dbmappings/profiles.go @@ -0,0 +1,23 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package dbmappings + +import ( + // stdlib + "time" +) + +type Profiles struct { + Id int `db:"id"` + Player_id int `db:"player_id"` + Nickname string `db:"nickname"` + TelegramNickname string `db:"telegram_nickname"` + Level_id int `db:"level_id"` + Exp int `db:"exp"` + Egg_exp int `db:"egg_exp"` + Power int `db:"power"` + Weapon_id int `db:"weapon_id"` + Crystalls int `db:"crystalls"` + Created_at *time.Time `db:"created_at"` +} diff --git a/lib/migrations/1_hello.go b/lib/migrations/1_hello.go new file mode 100644 index 0000000..9207550 --- /dev/null +++ b/lib/migrations/1_hello.go @@ -0,0 +1,18 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" + "log" +) + +// First migration, added for testing purposes + +func HelloUp(tx *sql.Tx) error { + log.Printf("Migration framework loaded. All systems are OK.") + + return nil +} diff --git a/lib/migrations/2_create_players.go b/lib/migrations/2_create_players.go new file mode 100644 index 0000000..3758824 --- /dev/null +++ b/lib/migrations/2_create_players.go @@ -0,0 +1,38 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +func CreatePlayersUp(tx *sql.Tx) error { + create_request := "CREATE TABLE `players` (" + create_request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID игрока'," + create_request += "`telegram_id` int(11) NOT NULL COMMENT 'ID в телеграме'," + create_request += "`league_id` int(11) COMMENT 'ID лиги' DEFAULT 0," + create_request += "`squad_id` int(11) COMMENT 'ID отряда' DEFAULT 0," + create_request += "`status` varchar(191) COMMENT 'Статус в лиге' DEFAULT 'common'," + create_request += "`created_at` datetime NOT NULL COMMENT 'Добавлен в базу'," + create_request += "`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Время последнего обновления'," + create_request += "PRIMARY KEY (`id`)," + create_request += "UNIQUE KEY `id` (`id`)," + create_request += "KEY `players_created_at` (`created_at`)," + create_request += "KEY `players_updated_at` (`updated_at`)" + create_request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Зарегистрированные игроки';" + _, err := tx.Exec(create_request) + if err != nil { + return err + } + return nil +} + +func CreatePlayersDown(tx *sql.Tx) error { + _, err := tx.Exec("DROP TABLE `players`;") + if err != nil { + return err + } + return nil +} diff --git a/lib/migrations/3_create_profiles.go b/lib/migrations/3_create_profiles.go new file mode 100644 index 0000000..29c3aa7 --- /dev/null +++ b/lib/migrations/3_create_profiles.go @@ -0,0 +1,42 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +func CreateProfilesUp(tx *sql.Tx) error { + create_request := "CREATE TABLE `profiles` (" + create_request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID сохраненного профиля'," + create_request += "`player_id` int(11) NOT NULL COMMENT 'ID игрока в системе'," + create_request += "`nickname` varchar(191) NOT NULL COMMENT 'Ник игрока'," + create_request += "`telegram_nickname` varchar(191) NOT NULL COMMENT 'Ник в Телеграме (@)'," + create_request += "`level_id` int(11) NOT NULL COMMENT 'Уровень'," + create_request += "`exp` int(11) NOT NULL COMMENT 'Опыт'," + create_request += "`egg_exp` int(11) NOT NULL COMMENT 'Опыт яйца'," + create_request += "`power` int(11) NOT NULL COMMENT 'Сила без оружия'," + create_request += "`weapon_id` int(11) NOT NULL COMMENT 'Тип оружия'," + create_request += "`crystalls` int(11) NOT NULL COMMENT 'Кристаллы'," + create_request += "`created_at` datetime NOT NULL COMMENT 'Добавлен в базу'," + create_request += "PRIMARY KEY (`id`)," + create_request += "UNIQUE KEY `id` (`id`)," + create_request += "KEY `profiles_created_at` (`created_at`)," + create_request += "KEY `profiles_nickname` (`nickname`)" + create_request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Профили зарегистрированных игроков';" + _, err := tx.Exec(create_request) + if err != nil { + return err + } + return nil +} + +func CreateProfilesDown(tx *sql.Tx) error { + _, err := tx.Exec("DROP TABLE `profiles`;") + if err != nil { + return err + } + return nil +} diff --git a/lib/migrations/4_create_pokememes.go b/lib/migrations/4_create_pokememes.go new file mode 100644 index 0000000..a9c2938 --- /dev/null +++ b/lib/migrations/4_create_pokememes.go @@ -0,0 +1,44 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +func CreatePokememesUp(tx *sql.Tx) error { + create_request := "CREATE TABLE `pokememes` (" + create_request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID покемема'," + create_request += "`grade` int(11) NOT NULL COMMENT 'Поколение покемема'," + create_request += "`name` varchar(191) NOT NULL COMMENT 'Имя покемема'," + create_request += "`description` TEXT NOT NULL COMMENT 'Описание покемема'," + create_request += "`attack` int(11) NOT NULL COMMENT 'Атака'," + create_request += "`hp` int(11) NOT NULL COMMENT 'Здоровье'," + create_request += "`mp` int(11) NOT NULL COMMENT 'МР'," + create_request += "`defence` int(11) NOT NULL COMMENT 'Защита'," + create_request += "`price` int(11) NOT NULL COMMENT 'Стоимость'," + create_request += "`purchaseable` bool NOT NULL DEFAULT true COMMENT 'Можно купить?'," + create_request += "`image_url` varchar(191) NOT NULL COMMENT 'Изображение покемема'," + create_request += "`player_id` int(11) NOT NULL COMMENT 'Кто добавил в базу'," + create_request += "`created_at` datetime NOT NULL COMMENT 'Добавлен в базу'," + create_request += "PRIMARY KEY (`id`)," + create_request += "UNIQUE KEY `id` (`id`)," + create_request += "KEY `pokememes_created_at` (`created_at`)," + create_request += "KEY `pokememes_player_id` (`player_id`)" + create_request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Покемемы';" + _, err := tx.Exec(create_request) + if err != nil { + return err + } + return nil +} + +func CreatePokememesDown(tx *sql.Tx) error { + _, err := tx.Exec("DROP TABLE `pokememes`;") + if err != nil { + return err + } + return nil +} diff --git a/lib/migrations/5_create_locations.go b/lib/migrations/5_create_locations.go new file mode 100644 index 0000000..bdfdea9 --- /dev/null +++ b/lib/migrations/5_create_locations.go @@ -0,0 +1,61 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +func CreateLocationsUp(tx *sql.Tx) error { + create_request := "CREATE TABLE `locations` (" + create_request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID локации'," + create_request += "`symbol` varchar(191) COLLATE 'utf8mb4_unicode_520_ci' NOT NULL COMMENT 'Символ локации'," + create_request += "`name` varchar(191) NOT NULL COMMENT 'Имя локации'," + create_request += "`created_at` datetime NOT NULL COMMENT 'Добавлена в базу'," + create_request += "PRIMARY KEY (`id`)," + create_request += "UNIQUE KEY `id` (`id`)," + create_request += "KEY `locations_created_at` (`created_at`)" + create_request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Локации';" + _, err := tx.Exec(create_request) + if err != nil { + return err + } + + // Insert locations + _, err2 := tx.Exec("INSERT INTO `locations` VALUES(NULL, ':evergreen_tree:', 'Лес', NOW());") + if err2 != nil { + return err2 + } + _, err3 := tx.Exec("INSERT INTO `locations` VALUES(NULL, '⛰', 'Горы', NOW());") + if err3 != nil { + return err2 + } + _, err4 := tx.Exec("INSERT INTO `locations` VALUES(NULL, ':rowboat:', 'Озеро', NOW());") + if err4 != nil { + return err2 + } + _, err5 := tx.Exec("INSERT INTO `locations` VALUES(NULL, '🏙:', 'Город', NOW());") + if err5 != nil { + return err2 + } + _, err6 := tx.Exec("INSERT INTO `locations` VALUES(NULL, '🏛', 'Катакомбы', NOW());") + if err6 != nil { + return err2 + } + _, err7 := tx.Exec("INSERT INTO `locations` VALUES(NULL, ':church:', 'Кладбище', NOW());") + if err7 != nil { + return err2 + } + + return nil +} + +func CreateLocationsDown(tx *sql.Tx) error { + _, err := tx.Exec("DROP TABLE `locations`;") + if err != nil { + return err + } + return nil +} diff --git a/lib/migrations/6_create_elements.go b/lib/migrations/6_create_elements.go new file mode 100644 index 0000000..706eea6 --- /dev/null +++ b/lib/migrations/6_create_elements.go @@ -0,0 +1,86 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +func CreateElementsUp(tx *sql.Tx) error { + create_request := "CREATE TABLE `elements` (" + create_request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID элемента'," + create_request += "`symbol` varchar(191) COLLATE 'utf8mb4_unicode_520_ci' NOT NULL COMMENT 'Символ элемента'," + create_request += "`name` varchar(191) NOT NULL COMMENT 'Имя элемента'," + create_request += "`league_id` int(11) NOT NULL COMMENT 'ID родной лиги'," + create_request += "`created_at` datetime NOT NULL COMMENT 'Добавлен в базу'," + create_request += "PRIMARY KEY (`id`)," + create_request += "UNIQUE KEY `id` (`id`)," + create_request += "KEY `elements_created_at` (`created_at`)" + create_request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Элементы';" + _, err := tx.Exec(create_request) + if err != nil { + return err + } + + // Insert elements + _, err2 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '👊', 'Боевой', 1, NOW());") + if err2 != nil { + return err2 + } + _, err3 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '🌀', 'Летающий', 1, NOW());") + if err3 != nil { + return err3 + } + _, err4 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '💀', 'Ядовитый', 1, NOW());") + if err4 != nil { + return err4 + } + _, err5 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '🗿', 'Каменный', 1, NOW());") + if err5 != nil { + return err5 + } + _, err6 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '🔥', 'Огненный', 2, NOW());") + if err6 != nil { + return err6 + } + _, err7 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '⚡', 'Электрический', 2, NOW());") + if err7 != nil { + return err7 + } + _, err8 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '💧', 'Водяной', 2, NOW());") + if err8 != nil { + return err8 + } + _, err9 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '🍀', 'Травяной', 2, NOW());") + if err9 != nil { + return err9 + } + _, err10 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '💩', 'Шоколадный', 3, NOW());") + if err10 != nil { + return err10 + } + _, err11 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '👁', 'Психический', 3, NOW());") + if err11 != nil { + return err11 + } + _, err12 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '👿', 'Темный', 3, NOW());") + if err12 != nil { + return err12 + } + _, err13 := tx.Exec("INSERT INTO `elements` VALUES(NULL, '⌛', 'Времени', 1, NOW());") + if err13 != nil { + return err13 + } + + return nil +} + +func CreateElementsDown(tx *sql.Tx) error { + _, err := tx.Exec("DROP TABLE `elements`;") + if err != nil { + return err + } + return nil +} diff --git a/lib/migrations/7_create_leagues.go b/lib/migrations/7_create_leagues.go new file mode 100644 index 0000000..e846433 --- /dev/null +++ b/lib/migrations/7_create_leagues.go @@ -0,0 +1,49 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +func CreateLeaguesUp(tx *sql.Tx) error { + create_request := "CREATE TABLE `leagues` (" + create_request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID лиги'," + create_request += "`symbol` varchar(191) COLLATE 'utf8mb4_unicode_520_ci' NOT NULL COMMENT 'Символ лиги'," + create_request += "`name` varchar(191) NOT NULL COMMENT 'Имя лиги'," + create_request += "`created_at` datetime NOT NULL COMMENT 'Добавлена в базу'," + create_request += "PRIMARY KEY (`id`)," + create_request += "UNIQUE KEY `id` (`id`)," + create_request += "KEY `leagues_created_at` (`created_at`)" + create_request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Лиги';" + _, err := tx.Exec(create_request) + if err != nil { + return err + } + + // Insert locations + _, err2 := tx.Exec("INSERT INTO `leagues` VALUES(NULL, ':u7533:', 'ИНСТИНКТ', NOW());") + if err2 != nil { + return err2 + } + _, err3 := tx.Exec("INSERT INTO `leagues` VALUES(NULL, ':u6e80', 'ОТВАГА', NOW());") + if err3 != nil { + return err2 + } + _, err4 := tx.Exec("INSERT INTO `leagues` VALUES(NULL, ':u7a7a:', 'МИСТИКА', NOW());") + if err4 != nil { + return err2 + } + + return nil +} + +func CreateLeaguesDown(tx *sql.Tx) error { + _, err := tx.Exec("DROP TABLE `leagues`;") + if err != nil { + return err + } + return nil +} diff --git a/lib/migrations/8_create_relations.go b/lib/migrations/8_create_relations.go new file mode 100644 index 0000000..c73b061 --- /dev/null +++ b/lib/migrations/8_create_relations.go @@ -0,0 +1,52 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "database/sql" +) + +func CreateRelationsUp(tx *sql.Tx) error { + create_request := "CREATE TABLE `pokememes_locations` (" + create_request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID связи'," + create_request += "`pokememe_id` int(11) NOT NULL COMMENT 'ID покемема'," + create_request += "`location_id` int(11) NOT NULL COMMENT 'ID локации'," + create_request += "`created_at` datetime NOT NULL COMMENT 'Добавлено в базу'," + create_request += "PRIMARY KEY (`id`)," + create_request += "UNIQUE KEY `id` (`id`)," + create_request += "KEY `pokememes_locations_created_at` (`created_at`)" + create_request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Связь Покемемы-Локации';" + _, err := tx.Exec(create_request) + if err != nil { + return err + } + + create_request = "CREATE TABLE `pokememes_elements` (" + create_request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID связи'," + create_request += "`pokememe_id` int(11) NOT NULL COMMENT 'ID покемема'," + create_request += "`element_id` int(11) NOT NULL COMMENT 'ID элемента'," + create_request += "`created_at` datetime NOT NULL COMMENT 'Добавлено в базу'," + create_request += "PRIMARY KEY (`id`)," + create_request += "UNIQUE KEY `id` (`id`)," + create_request += "KEY `pokememes_elements_created_at` (`created_at`)" + create_request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Связь Покемемы-Элементы';" + _, err2 := tx.Exec(create_request) + if err2 != nil { + return err2 + } + return nil +} + +func CreateRelationsDown(tx *sql.Tx) error { + _, err := tx.Exec("DROP TABLE `pokememes_locations`;") + if err != nil { + return err + } + _, err2 := tx.Exec("DROP TABLE `pokememes_elements`;") + if err2 != nil { + return err2 + } + return nil +} diff --git a/lib/migrations/exported.go b/lib/migrations/exported.go new file mode 100644 index 0000000..3c7394e --- /dev/null +++ b/lib/migrations/exported.go @@ -0,0 +1,20 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // local + "../appcontext" + "../migrations/migrationsinterface" +) + +var ( + c *appcontext.Context +) + +func New(ac *appcontext.Context) { + c = ac + m := &Migrations{} + c.RegisterMigrationsInterface(migrationsinterface.MigrationsInterface(m)) +} diff --git a/lib/migrations/migrations.go b/lib/migrations/migrations.go new file mode 100644 index 0000000..757a53d --- /dev/null +++ b/lib/migrations/migrations.go @@ -0,0 +1,42 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrations + +import ( + // stdlib + "log" + // 3rd-party + "github.com/pressly/goose" +) + +type Migrations struct {} + +func (m *Migrations) Init() { + log.Printf("Initializing migrations...") + // All migrations are here + goose.AddNamedMigration("1_hello.go", HelloUp, nil) + goose.AddNamedMigration("2_create_players.go", CreatePlayersUp, CreatePlayersDown) + goose.AddNamedMigration("3_create_profiles.go", CreateProfilesUp, CreateProfilesDown) + goose.AddNamedMigration("4_create_pokememes.go", CreatePokememesUp, CreatePokememesDown) + goose.AddNamedMigration("5_create_locations.go", CreateLocationsUp, CreateLocationsDown) + goose.AddNamedMigration("6_create_elements.go", CreateElementsUp, CreateElementsDown) + goose.AddNamedMigration("7_create_leagues.go", CreateLeaguesUp, CreateLeaguesDown) + goose.AddNamedMigration("8_create_relations.go", CreateRelationsUp, CreateRelationsDown) +} + +func (m *Migrations) Migrate() error { + log.Printf("Starting database migrations...") + err := goose.Up(c.Db.DB, ".") + if err != nil { + log.Fatal(err) + + return err + } + + return nil +} + +func (m *Migrations) SetDialect(dialect string) error { + return goose.SetDialect(dialect) +} diff --git a/lib/migrations/migrationsinterface/migrationsinterface.go b/lib/migrations/migrationsinterface/migrationsinterface.go new file mode 100644 index 0000000..9a5bee1 --- /dev/null +++ b/lib/migrations/migrationsinterface/migrationsinterface.go @@ -0,0 +1,10 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package migrationsinterface + +type MigrationsInterface interface { + Init() + Migrate() error + SetDialect(dialect string) error +} diff --git a/lib/parsers/exported.go b/lib/parsers/exported.go new file mode 100644 index 0000000..3ac5960 --- /dev/null +++ b/lib/parsers/exported.go @@ -0,0 +1,22 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package parsers + +import ( + // local + "../appcontext" + "../parsers/parsersinterface" +) + +var ( + c *appcontext.Context +) + +type Parsers struct {} + +func New(ac *appcontext.Context) { + c = ac + p := &Parsers{} + c.RegisterParsersInterface(parsersinterface.ParsersInterface(p)) +} diff --git a/lib/parsers/parsersinterface/parsersinterface.go b/lib/parsers/parsersinterface/parsersinterface.go new file mode 100644 index 0000000..1559470 --- /dev/null +++ b/lib/parsers/parsersinterface/parsersinterface.go @@ -0,0 +1,14 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package parsersinterface + +import ( + // local + "../../dbmappings" +) + + +type ParsersInterface interface { + ParsePokememe(text string, player_raw dbmappings.Players) string +} diff --git a/lib/parsers/pokememe.go b/lib/parsers/pokememe.go new file mode 100644 index 0000000..d4cc050 --- /dev/null +++ b/lib/parsers/pokememe.go @@ -0,0 +1,57 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package parsers + +import ( + // stdlib + "fmt" + "log" + "strings" + // local + "../dbmappings" +) + +func (p *Parsers) ParsePokememe(text string, player_raw dbmappings.Players) string { + var defendable_pokememe bool = false + pokememe_info_strings := strings.Split(text, "\n") + pokememe_info_runed_strings := make([][]rune, 0) + for i := range(pokememe_info_strings) { + pokememe_info_runed_strings = append(pokememe_info_runed_strings, []rune(pokememe_info_strings[i])) + } + + if len(pokememe_info_runed_strings) == 13 { + defendable_pokememe = true + } + fmt.Println(defendable_pokememe) + + // Getting elements + elements := []dbmappings.Elements{} + element_emojis := make([]string, 0) + element_emojis = append(element_emojis, string(pokememe_info_runed_strings[4][11])) + if len(pokememe_info_runed_strings[4]) > 12 { + element_emojis = append(element_emojis, string(pokememe_info_runed_strings[4][13])) + } + if len(pokememe_info_runed_strings[4]) > 14 { + element_emojis = append(element_emojis, string(pokememe_info_runed_strings[4][15])) + } + + err := c.Db.Select(&elements, "SELECT * FROM elements WHERE symbol IN ('" + strings.Join(element_emojis, "', '") + "')") + if err != nil { + log.Printf(err.Error()) + return "fail" + } + + grade := string(pokememe_info_runed_strings[0][0]) + name := string(pokememe_info_runed_strings[0][3:]) + description := string(pokememe_info_runed_strings[1]) + log.Printf("Pokememe grade: " + grade) + log.Printf("Pokememe name: " + name) + log.Printf("Pokememe description: " + description) + log.Printf("Elements:") + for i := range(elements) { + log.Printf(elements[i].Symbol + " " + elements[i].Name) + } + + return "ok" +} diff --git a/lib/router/router.go b/lib/router/router.go index 4375c51..d2d449a 100644 --- a/lib/router/router.go +++ b/lib/router/router.go @@ -5,11 +5,13 @@ package router import ( // stdlib + "fmt" "log" "regexp" // 3rd party "gopkg.in/telegram-bot-api.v4" // local + "../dbmappings" "../talkers" ) @@ -20,6 +22,18 @@ type Router struct {} // If command doesn't exist, it's "fail" func (r *Router) RouteRequest(update tgbotapi.Update) string { text := update.Message.Text + user_id := update.Message.From.ID + + player_raw := dbmappings.Players{} + err := c.Db.Get(&player_raw, c.Db.Rebind("SELECT * FROM players WHERE telegram_id=?"), user_id) + if err != nil { + log.Printf("Message user not found in database.") + log.Printf(err.Error()) + } else { + log.Printf("Message user found in database.") + } + + fmt.Println(player_raw) // Regular expressions var durakMsg = regexp.MustCompile("(Д|д)(У|у)(Р|р)(А|а|Е|е|О|о)") @@ -28,23 +42,53 @@ func (r *Router) RouteRequest(update tgbotapi.Update) string { var ebMsg = regexp.MustCompile("(Е|е|Ё|ё)(Б|б)(\\s|А|а|Т|т|У|у|Е|е|Ё|ё|И|и)") var piMsg = regexp.MustCompile("(П|п)(И|и)(З|з)(Д|д)") var helpMsg = regexp.MustCompile("/help\\z") + var helloMsg = regexp.MustCompile("/start\\z") - switch { - case helpMsg.MatchString(text): - talkers.HelpMessage(c.Bot, update) - case huMsg.MatchString(text): - talkers.MatMessage(c.Bot, update) - case blMsg.MatchString(text): - talkers.MatMessage(c.Bot, update) - case ebMsg.MatchString(text): - talkers.MatMessage(c.Bot, update) - case piMsg.MatchString(text): - talkers.MatMessage(c.Bot, update) - case durakMsg.MatchString(text): - talkers.DurakMessage(c.Bot, update) - default: - log.Printf("User posted unknown command.") - return "fail" + var pokememeMsg = regexp.MustCompile("(Уровень)(.+)(Опыт)(.+)\n(Элементы:)(.+)\n(.+)(💙MP)") + + if update.Message.ForwardFrom != nil { + if update.Message.ForwardFrom.ID != 360402625 { + log.Printf("Forward from another user or bot. Ignoring") + } else { + log.Printf("Forward from PokememBro bot! Processing...") + if pokememeMsg.MatchString(text) { + if player_raw.Id != 0 { + log.Printf("Pokememe posted!") + c.Parsers.ParsePokememe(text, player_raw) + } else { + talkers.AnyMessageUnauthorized(c.Bot, update) + } + } else { + log.Printf(text) + } + } + } else { + // Direct messages from user + switch { + case helloMsg.MatchString(text): + if player_raw.Id != 0 { + talkers.HelloMessageAuthorized(c.Bot, update, player_raw) + } else { + talkers.HelloMessageUnauthorized(c.Bot, update) + } + // Help + case helpMsg.MatchString(text): + talkers.HelpMessage(c.Bot, update) + // Easter eggs + case huMsg.MatchString(text): + talkers.MatMessage(c.Bot, update) + case blMsg.MatchString(text): + talkers.MatMessage(c.Bot, update) + case ebMsg.MatchString(text): + talkers.MatMessage(c.Bot, update) + case piMsg.MatchString(text): + talkers.MatMessage(c.Bot, update) + case durakMsg.MatchString(text): + talkers.DurakMessage(c.Bot, update) + default: + log.Printf("User posted unknown command.") + return "fail" + } } return "ok" diff --git a/lib/talkers/errors.go b/lib/talkers/errors.go new file mode 100644 index 0000000..6d020bf --- /dev/null +++ b/lib/talkers/errors.go @@ -0,0 +1,19 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package talkers + +import ( + // 3rd party + "gopkg.in/telegram-bot-api.v4" +) + +func AnyMessageUnauthorized(bot *tgbotapi.BotAPI, update tgbotapi.Update) { + error_message := "Извини, действие для тебя недоступно. Возможно, у меня нет твоего профиля или же твои права недостаточны для совершения данного действия\n\n" + error_message += "Если тебе кажется, что это ошибка, пиши @fat0troll.\n" + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, error_message) + msg.ParseMode = "Markdown" + + bot.Send(msg) +} diff --git a/lib/talkers/hello.go b/lib/talkers/hello.go new file mode 100644 index 0000000..26831d0 --- /dev/null +++ b/lib/talkers/hello.go @@ -0,0 +1,32 @@ +// i2_bot – Instinct PokememBro Bot +// Copyright (c) 2017 Vladimir "fat0troll" Hodakov + +package talkers + +import ( + // 3rd party + "gopkg.in/telegram-bot-api.v4" + // local + "../dbmappings" +) + +func HelloMessageUnauthorized(bot *tgbotapi.BotAPI, update tgbotapi.Update) { + hello_message := "*Бот Инстинкта приветствует тебя!*\n\n" + hello_message += "Для начала работы с ботом, пожалуйста, перешли от бота игры @PokememBroBot профиль героя.\n" + hello_message += "Все дальнейшие действия с ботом возможны лишь при наличии профиля игрока." + + msg := tgbotapi.NewMessage(update.Message.Chat.ID, hello_message) + msg.ParseMode = "Markdown" + + bot.Send(msg) +} + +func HelloMessageAuthorized(bot *tgbotapi.BotAPI, update tgbotapi.Update, player_raw dbmappings.Players) { + hello_message := "*Бот Инстинкта приветствует тебя. Снова.*\n\n" + hello_message += "Привет, " + update.Message.From.FirstName + " " + update.Message.From.LastName + "!\n" + hello_message += "Последнее обновление информации о тебе: " + player_raw.Updated_at.Format("02.01.2006 15:04:05 -0700") + msg := tgbotapi.NewMessage(update.Message.Chat.ID, hello_message) + msg.ParseMode = "Markdown" + + bot.Send(msg) +} diff --git a/lib/talkers/help.go b/lib/talkers/help.go index 2b006f8..f3fae7c 100644 --- a/lib/talkers/help.go +++ b/lib/talkers/help.go @@ -11,7 +11,7 @@ import ( ) func HelpMessage(bot *tgbotapi.BotAPI, update tgbotapi.Update) { - help_message := "*Бот Инстинкта. Версия обезшпионенная и улучшенная.*\n\n" + help_message := "*Бот Инстинкта Enchanched.*\n\n" help_message += "Текущая версия: *" + config.VERSION + "*\n\n" help_message += "Список команд:\n\n" help_message += "+ /help – выводит данное сообщение\n"