Broadcast messages are now stored in database
This commit is contained in:
		
							
								
								
									
										19
									
								
								lib/dbmapping/broadcast.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/dbmapping/broadcast.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| // i2_bot – Instinct PokememBro Bot | ||||
| // Copyright (c) 2017 Vladimir "fat0troll" Hodakov | ||||
|  | ||||
| package dbmapping | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // Broadcast is a struct, which represents `broadcast` table item in databse. | ||||
| type Broadcast struct { | ||||
| 	ID            int       `db:"id"` | ||||
| 	Text          string    `db:"text"` | ||||
| 	BroadcastType string    `db:"broadcast_type"` | ||||
| 	Status        string    `db:"status"` | ||||
| 	AuthorID      int       `db:"author_id"` | ||||
| 	CreatedAt     time.Time `db:"created_at"` | ||||
| } | ||||
							
								
								
									
										69
									
								
								lib/getters/broadcasts.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								lib/getters/broadcasts.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| // i2_bot – Instinct PokememBro Bot | ||||
| // Copyright (c) 2017 Vladimir "fat0troll" Hodakov | ||||
|  | ||||
| package getters | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"log" | ||||
| 	"time" | ||||
| 	// local | ||||
| 	"../dbmapping" | ||||
| ) | ||||
|  | ||||
| // CreateBroadcastMessage creates broadcast message item in database | ||||
| func (g *Getters) CreateBroadcastMessage(playerRaw *dbmapping.Player, messageBody string, broadcastType string) (dbmapping.Broadcast, bool) { | ||||
| 	messageRaw := dbmapping.Broadcast{} | ||||
| 	messageRaw.Text = messageBody | ||||
| 	messageRaw.Status = "new" | ||||
| 	messageRaw.BroadcastType = broadcastType | ||||
| 	messageRaw.AuthorID = playerRaw.ID | ||||
| 	messageRaw.CreatedAt = time.Now().UTC() | ||||
| 	_, err := c.Db.NamedExec("INSERT INTO broadcasts VALUES(NULL, :text, :broadcast_type, :status, :author_id, :created_at)", &messageRaw) | ||||
| 	if err != nil { | ||||
| 		log.Printf(err.Error()) | ||||
| 		return messageRaw, false | ||||
| 	} | ||||
| 	err2 := c.Db.Get(&messageRaw, c.Db.Rebind("SELECT * FROM broadcasts WHERE author_id=? AND text=?"), messageRaw.AuthorID, messageRaw.Text) | ||||
| 	if err2 != nil { | ||||
| 		log.Println(err2) | ||||
| 		return messageRaw, false | ||||
| 	} | ||||
|  | ||||
| 	return messageRaw, true | ||||
| } | ||||
|  | ||||
| // GetBroadcastMessageByID returns dbmapping.Broadcast instance with given ID. | ||||
| func (g *Getters) 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 { | ||||
| 		log.Println(err) | ||||
| 		return messageRaw, false | ||||
| 	} | ||||
|  | ||||
| 	return messageRaw, true | ||||
| } | ||||
|  | ||||
| // UpdateBroadcastMessageStatus updates broadcast message status | ||||
| func (g *Getters) 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 { | ||||
| 		log.Println(err) | ||||
| 		return messageRaw, false | ||||
| 	} | ||||
| 	messageRaw.Status = messageStatus | ||||
| 	_, err = c.Db.NamedExec("UPDATE broadcasts SET status=:status WHERE id=:id", &messageRaw) | ||||
| 	if err != nil { | ||||
| 		log.Printf(err.Error()) | ||||
| 		return messageRaw, false | ||||
| 	} | ||||
| 	err = c.Db.Get(&messageRaw, c.Db.Rebind("SELECT * FROM broadcasts WHERE author_id=? AND text=?"), messageRaw.AuthorID, messageRaw.Text) | ||||
| 	if err != nil { | ||||
| 		log.Println(err) | ||||
| 		return messageRaw, false | ||||
| 	} | ||||
|  | ||||
| 	return messageRaw, true | ||||
| } | ||||
| @@ -13,6 +13,9 @@ import ( | ||||
| // 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) | ||||
| 	GetOrCreateChat(update *tgbotapi.Update) (dbmapping.Chat, bool) | ||||
| 	GetChatByID(chatID int) (dbmapping.Chat, bool) | ||||
| 	GetAllPrivateChats() ([]dbmapping.Chat, bool) | ||||
|   | ||||
							
								
								
									
										37
									
								
								lib/migrations/19_create_broadcasts.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								lib/migrations/19_create_broadcasts.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| // i2_bot – Instinct PokememBro Bot | ||||
| // Copyright (c) 2017 Vladimir "fat0troll" Hodakov | ||||
|  | ||||
| package migrations | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"database/sql" | ||||
| ) | ||||
|  | ||||
| func CreateBroadcastsUp(tx *sql.Tx) error { | ||||
| 	request := "CREATE TABLE `broadcasts` (" | ||||
| 	request += "`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID сообщения'," | ||||
| 	request += "`text` text NOT NULL COMMENT 'Тело сообщения'," | ||||
| 	request += "`broadcast_type` varchar(191) NOT NULL COMMENT 'Тип широковещательного сообщения'," | ||||
| 	request += "`status` varchar(191) NOT NULL DEFAULT 'new' COMMENT 'Статус сообщения'," | ||||
| 	request += "`author_id` int(11) NOT NULL COMMENT 'ID автора'," | ||||
| 	request += "`created_at` datetime NOT NULL COMMENT 'Добавлено в базу'," | ||||
| 	request += "PRIMARY KEY (`id`)," | ||||
| 	request += "UNIQUE KEY `id` (`id`)," | ||||
| 	request += "KEY `broadcasts_created_at` (`created_at`)" | ||||
| 	request += ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Широковещательные сообщения';" | ||||
| 	_, err := tx.Exec(request) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func CreateBroadcastsDown(tx *sql.Tx) error { | ||||
| 	_, err := tx.Exec("DROP TABLE `broadcasts`;") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -33,6 +33,7 @@ func (m *Migrations) Init() { | ||||
| 	goose.AddNamedMigration("16_change_chat_type_column.go", ChangeChatTypeColumnUp, ChangeChatTypeColumnDown) | ||||
| 	goose.AddNamedMigration("17_change_profile_pokememes_columns.go", ChangeProfilePokememesColumnsUp, ChangeProfilePokememesColumnsDown) | ||||
| 	goose.AddNamedMigration("18_add_pokememes_wealth.go", AddPokememesWealthUp, AddPokememesWealthDown) | ||||
| 	goose.AddNamedMigration("19_create_broadcasts.go", CreateBroadcastsUp, CreateBroadcastsDown) | ||||
| } | ||||
|  | ||||
| func (m *Migrations) Migrate() error { | ||||
|   | ||||
| @@ -50,6 +50,7 @@ func (r *Router) RouteRequest(update tgbotapi.Update) string { | ||||
|  | ||||
| 	// Owner commands | ||||
| 	var sendAllMsg = regexp.MustCompile("/send_all(.+)") | ||||
| 	var sendConfirmMsg = regexp.MustCompile(`/send_confirm(\s)(\d+)`) | ||||
|  | ||||
| 	// Forwards | ||||
| 	var pokememeMsg = regexp.MustCompile("(Уровень)(.+)(Опыт)(.+)\n(Элементы:)(.+)\n(.+)(💙MP)") | ||||
| @@ -131,7 +132,13 @@ func (r *Router) RouteRequest(update tgbotapi.Update) string { | ||||
| 		// Admin commands | ||||
| 		case sendAllMsg.MatchString(text): | ||||
| 			if c.Getters.PlayerBetterThan(&playerRaw, "admin") { | ||||
| 				c.Talkers.AdminBroadcastMessage(update) | ||||
| 				c.Talkers.AdminBroadcastMessageCompose(update, &playerRaw) | ||||
| 			} else { | ||||
| 				c.Talkers.AnyMessageUnauthorized(update) | ||||
| 			} | ||||
| 		case sendConfirmMsg.MatchString(text): | ||||
| 			if c.Getters.PlayerBetterThan(&playerRaw, "admin") { | ||||
| 				c.Talkers.AdminBroadcastMessageSend(update, &playerRaw) | ||||
| 			} else { | ||||
| 				c.Talkers.AnyMessageUnauthorized(update) | ||||
| 			} | ||||
|   | ||||
| @@ -3,16 +3,68 @@ | ||||
|  | ||||
| package talkers | ||||
|  | ||||
| import ( // stdlib | ||||
| 	// 3rd party | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	// 3rd party | ||||
| 	"github.com/go-telegram-bot-api/telegram-bot-api" | ||||
| 	// local | ||||
| 	"../dbmapping" | ||||
| ) | ||||
|  | ||||
| // AdminBroadcastMessage sends message to all private chats with bot | ||||
| func (t *Talkers) AdminBroadcastMessage(update tgbotapi.Update) string { | ||||
| 	broadcastingMessageBody := strings.Replace(update.Message.Text, "/send_all", "", 1) | ||||
| // 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.Getters.GetAllPrivateChats() | ||||
| 	if !ok { | ||||
| @@ -30,6 +82,11 @@ func (t *Talkers) AdminBroadcastMessage(update tgbotapi.Update) string { | ||||
| 		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) | ||||
|   | ||||
| @@ -30,7 +30,8 @@ type TalkersInterface interface { | ||||
| 	AnyMessageUnauthorized(update tgbotapi.Update) | ||||
| 	GetterError(update tgbotapi.Update) | ||||
|  | ||||
| 	AdminBroadcastMessage(update tgbotapi.Update) string | ||||
| 	AdminBroadcastMessageCompose(update tgbotapi.Update, playerRaw *dbmapping.Player) string | ||||
| 	AdminBroadcastMessageSend(update tgbotapi.Update, playerRaw *dbmapping.Player) string	 | ||||
|  | ||||
| 	DurakMessage(update tgbotapi.Update) | ||||
| 	MatMessage(update tgbotapi.Update) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user