userGroup handling. Menus. Commands.

Signed-off-by: Ettore Dreucci <ettore.dreucci@gmail.com>
This commit is contained in:
2018-08-27 00:39:34 +02:00
parent b73cb0b12e
commit 43a047c3f3
9 changed files with 445 additions and 229 deletions

154
src/manageMsg.go Normal file
View File

@@ -0,0 +1,154 @@
package main
import (
"encoding/json"
"log"
"strconv"
tb "gopkg.in/tucnak/telebot.v2"
)
func closeMsgMenu(storedMsg *tb.StoredMessage) error {
_, err := bot.EditReplyMarkup(storedMsg, &tb.ReplyMarkup{
InlineKeyboard: nil,
})
if err != nil {
log.Printf("Error modifying the message: %v", err)
}
return nil
}
func setLastMsgPerUser(userID int, msg *tb.Message) error {
storedMsg := tb.StoredMessage{
MessageID: strconv.Itoa(msg.ID),
ChatID: msg.Chat.ID}
jsonMsg, err := json.Marshal(storedMsg)
if err != nil {
log.Printf("Error in marshalling msg to json: %v", err)
return ErrJSONMarshall
}
err = redisClient.HSet(lastMsgPerUser, strconv.Itoa(userID), jsonMsg).Err()
if err != nil {
log.Printf("Error adding last message per user info in hash: %v", err)
return ErrRedisAddHash
}
return nil
}
func getLastMsgPerUser(userID int) (*tb.StoredMessage, error) {
msg, err := redisClient.HGet(lastMsgPerUser, strconv.Itoa(userID)).Result()
if err != nil {
log.Printf("Error retriving last msg per user info from hash: %v", err)
return nil, ErrRedisRetrieveHash
}
jsonMsg := &tb.StoredMessage{}
err = json.Unmarshal([]byte(msg), jsonMsg)
if err != nil {
log.Printf("Error unmarshalling last msg per user info: %v", err)
return nil, ErrJSONUnmarshall
}
return jsonMsg, nil
}
func sendMsg(user *tb.User, msg string) error {
sentMsg, err := bot.Send(user, msg, &tb.SendOptions{
ParseMode: "Markdown",
})
if err != nil {
log.Printf("Error sending message to user: %v", err)
return ErrSendMsg
}
storedMsg, err := getLastMsgPerUser(user.ID)
if err != nil {
log.Printf("Error retriving last message per user: %v", err)
} else {
err = closeMsgMenu(storedMsg)
if err != nil {
log.Printf("Error modifying the message: %v", err)
}
}
err = setLastMsgPerUser(user.ID, sentMsg)
if err != nil {
log.Printf("Error setting last msg per user: %v", err)
return ErrSetLastMsg
}
return nil
}
func sendMsgWithMenu(user *tb.User, msg string) error {
var menu [][]tb.InlineButton
auth, err := isAuthrizedUser(user.ID)
if err != nil {
log.Printf("Error checking if user is authorized: %v", err)
}
admin, err := isBotAdmin(user.ID)
if err != nil {
log.Printf("Error checking if user is admin: %v", err)
}
if admin {
menu = adminInlineMenu
} else if auth {
menu = authInlineMenu
} else {
menu = genericInlineMenu
}
sentMsg, err := bot.Send(user, msg, &tb.SendOptions{
ReplyMarkup: &tb.ReplyMarkup{
InlineKeyboard: menu,
},
ParseMode: "Markdown",
})
if err != nil {
log.Printf("Error sending message to user: %v", err)
return ErrSendMsg
}
storedMsg, err := getLastMsgPerUser(user.ID)
if err != nil {
log.Printf("Error retriving last message per user: %v", err)
} else {
err = closeMsgMenu(storedMsg)
if err != nil {
log.Printf("Error modifying the message: %v", err)
}
}
err = setLastMsgPerUser(user.ID, sentMsg)
if err != nil {
log.Printf("Error setting last msg per user: %v", err)
return ErrSetLastMsg
}
return nil
}
func sendMsgWithSpecificMenu(user *tb.User, msg string, menu [][]tb.InlineButton) error {
sentMsg, err := bot.Send(user, msg, &tb.SendOptions{
ReplyMarkup: &tb.ReplyMarkup{
InlineKeyboard: menu,
},
ParseMode: "Markdown",
})
if err != nil {
log.Printf("Error sending message to user: %v", err)
return ErrSendMsg
}
storedMsg, err := getLastMsgPerUser(user.ID)
if err != nil {
log.Printf("Error retriving last message per user: %v", err)
} else {
err = closeMsgMenu(storedMsg)
if err != nil {
log.Printf("Error modifying the message: %v", err)
}
}
err = setLastMsgPerUser(user.ID, sentMsg)
if err != nil {
log.Printf("Error setting last msg per user: %v", err)
return ErrSetLastMsg
}
return nil
}

View File

@@ -12,7 +12,8 @@ import (
type userGroup int
const (
ugSoprano userGroup = iota
ugEsterno userGroup = iota
ugSoprano
ugContralto
ugTenore
ugBasso
@@ -41,6 +42,12 @@ func addUser(user *tb.User) error {
return ErrRedisAddHash
}
err = setUserGroups(user.ID, ugEsterno)
if err != nil {
log.Printf("Error setting user default group: %v", err)
return ErrRedisAddSet
}
return nil
}
@@ -86,11 +93,11 @@ func isStartedUser(userID int) (bool, error) {
return started, nil
}
func startUser(userID int, started bool) error {
func startUser(userID int, start bool) error {
if redisClient == nil {
return ErrNilPointer
}
if started {
if start {
err := redisClient.SAdd(startedUsers, strconv.Itoa(userID)).Err()
if err != nil {
log.Printf("Error adding token to set: %v", err)
@@ -145,6 +152,11 @@ func setUserGroups(userID int, groups ...userGroup) error {
var csvGroups string
for _, group := range groups {
csvGroups += strconv.Itoa(int(group)) + ","
err := redisClient.SAdd("ug"+strconv.Itoa(int(group)), strconv.Itoa(userID)).Err()
if err != nil {
log.Printf("Error adding user to usergroup set: %v", err)
return ErrRedisAddSet
}
}
err := redisClient.HSet(usersGroups, strconv.Itoa(userID), csvGroups).Err()
if err != nil {
@@ -162,7 +174,7 @@ func getUserGroups(userID int) ([]userGroup, error) {
csvGroups, err := redisClient.HGet(usersGroups, strconv.Itoa(userID)).Result()
if err != nil {
log.Printf("Error retrieving user groups: %v", err)
log.Printf("Error retriving user groups: %v", err)
return nil, ErrRedisRetrieveHash
}
var retGroups []userGroup
@@ -177,3 +189,47 @@ func getUserGroups(userID int) ([]userGroup, error) {
}
return retGroups, nil
}
func getUsersInGroup(group userGroup) ([]int, error) {
users, err := redisClient.SMembers("ug" + strconv.Itoa(int(group))).Result()
if err != nil {
log.Printf("Error retriving users in group: %v", err)
return nil, ErrRedisRetrieveSet
}
var retUsers []int
for _, user := range users {
intUser, err := strconv.Atoi(user)
if err != nil {
log.Printf("Error converting user ID: %v", err)
return nil, ErrAtoiConv
}
retUsers = append(retUsers, intUser)
}
return retUsers, nil
}
func convertUserGroups(groups []userGroup) []string {
var stringGroups []string
for _, group := range groups {
switch group {
case ugEsterno:
stringGroups = append(stringGroups, "Esterno al coro")
case ugSoprano:
stringGroups = append(stringGroups, "Soprano")
case ugContralto:
stringGroups = append(stringGroups, "Contralto")
case ugTenore:
stringGroups = append(stringGroups, "Tenore")
case ugBasso:
stringGroups = append(stringGroups, "Basso")
case ugCommissario:
stringGroups = append(stringGroups, "Commissario")
case ugReferente:
stringGroups = append(stringGroups, "Referente")
case ugPreparatore:
stringGroups = append(stringGroups, "Preparatore")
}
}
return stringGroups
}

View File

@@ -8,14 +8,15 @@ import (
)
const (
botToken = "botToken"
botInfo = "botInfo"
usersID = "usersID"
usersInfo = "usersInfo"
usersGroups = "usersGroups"
startedUsers = "startedUsers"
authUsers = "authUsers"
adminUsers = "adminUsers"
botToken = "botToken"
botInfo = "botInfo"
usersID = "usersID"
usersInfo = "usersInfo"
usersGroups = "usersGroups"
startedUsers = "startedUsers"
authUsers = "authUsers"
adminUsers = "adminUsers"
lastMsgPerUser = "lastMsgPerUser"
)
var redisClient *redis.Client

View File

@@ -54,7 +54,7 @@ func (i *stringSlice) Set(values string) error {
func getFlags() error {
const (
defaultInteractive = true
interactiveUsage = "False if the bot isn't executed on a tty"
interactiveUsage = "true/false if you want interactive/non-interactive usage"
defaultAddr = "127.0.0.1:6379"
addrUsage = "The address of the redis instance"
defaultPwd = ""

View File

@@ -18,26 +18,17 @@ const (
alreadyStartedMsg string = "Si, mi dica, che c'è?! Sono qui!"
restartMsg string = "Eccomi, sono tornato! Ha bisogno? Mi dica pure!"
stopMsg string = "Mi assenterò per qualche istante, d'altra parte anch'io ho pur diritto alla mia vita privata. Masino mi attende!"
unstoppableMsg string = "Non ci siamo... Io l'ho nominata AMMINISTRATORE, cosa crede?! Questo ruolo esige impegno! Non può certo bloccarmi!"
newAdminMsg string = "Beh allora, vediamo... Ah si, la nomino amministratore! Da grandi poteri derivano grandi responsabilità. Mi raccomando, non me ne faccia pentire!"
delAdminMsg string = "Ecco, che le avevo detto?! Mi sembrava di essere stato chiaro! Dovrò sollevarla dall'incarico... Mi spiace molto ma da ora in avanti non sarà più amministratore"
menuMsg string = "Ecco a lei, questo è l'elenco di tutto ciò che può chiedermi. Non mi disturbi con altre richieste!"
contactMsg string = "*BarandaBot*" +
"\nSe hai domande, suggerimenti o se vuoi segnalare bug e altri malfunzionamenti puoi contattare l'Altissimo con i seguenti mezzi di comunicazione:" +
"\n- \xF0\x9F\x90\xA6 _Piccione viaggiatore_: PlusCode - P99W+4Q Pisa, PI" +
"\n- \xF0\x9F\x93\xA7 _Mail_: telebot.corounipi@gmail.com" +
"\n- \xF0\x9F\x93\x82 _GitHub_: https://github.com/Noettore/barandaBot"
)
var genericCommands = map[string]bool{
"/start": true,
"/stop": true,
"/menu": true,
"/prossimoEvento": true,
}
var authCommands = map[string]bool{
"/prossimaProvaSezione": true,
"/prossimaProvaInsieme": true,
}
var adminCommands = map[string]bool{
"/autorizzaUtente": true,
"/aggiungiAdmin": true,
"/rimuoviAdmin": true,
}
var bot *tb.Bot
var botStatus botBool
var (
@@ -55,6 +46,8 @@ var (
ErrBotInit = errors.New("telegram: error in bot initialization")
//ErrBotConn is thrown when there is a connection problem
ErrBotConn = errors.New("telegram: cannot connect to bot")
//ErrSetLastMsg is thrown when it's not possible to set last message per user in hash
ErrSetLastMsg = errors.New("cannot set last message per user")
)
func botInit() error {
@@ -110,55 +103,6 @@ func botInit() error {
return nil
}
func sendMsg(user *tb.User, msg string) error {
_, err := bot.Send(user, msg)
if err != nil {
log.Printf("Error sending message to user: %v", err)
return ErrSendMsg
}
return nil
}
func sendMsgWithMenu(user *tb.User, msg string) error {
var menu [][]tb.InlineButton
auth, err := isAuthrizedUser(user.ID)
if err != nil {
log.Printf("Error checking if user is authorized: %v", err)
}
admin, err := isBotAdmin(user.ID)
if err != nil {
log.Printf("Error checking if user is admin: %v", err)
}
if admin {
menu = adminInlineMenu
} else if auth {
menu = authInlineMenu
} else {
menu = genericInlineMenu
}
_, err = bot.Send(user, msg, &tb.ReplyMarkup{
InlineKeyboard: menu,
})
if err != nil {
log.Printf("Error sending message to user: %v", err)
return ErrSendMsg
}
return nil
}
func sendMsgWithSpecificMenu(user *tb.User, msg string, menu [][]tb.InlineButton) error {
_, err := bot.Send(user, msg, &tb.ReplyMarkup{
InlineKeyboard: menu,
})
if err != nil {
log.Printf("Error sending message to user: %v", err)
return ErrSendMsg
}
return nil
}
func setBotPoller(upd *tb.Update) bool {
if upd.Message == nil {
return true

118
src/telegramCommands.go Normal file
View File

@@ -0,0 +1,118 @@
package main
import (
"log"
"strconv"
tb "gopkg.in/tucnak/telebot.v2"
)
var genericCommands = map[string]bool{
"/start": true,
"/stop": true,
"/menu": true,
"/userInfo": true,
"/botInfo": true,
"/prossimoEvento": true,
}
var authCommands = map[string]bool{
"/prossimaProvaSezione": true,
"/prossimaProvaInsieme": true,
}
var adminCommands = map[string]bool{
"/authUser": true,
"/addAdmin": true,
"/delAdmin": true,
}
func startCmd(u *tb.User) {
var msg string
isUser, err := isUser(u.ID)
if err != nil {
log.Printf("Error checking if ID is bot user: %v", err)
}
started, err := isStartedUser(u.ID)
if err != nil {
log.Printf("Error checking if user is started: %v", err)
}
if !started {
err = startUser(u.ID, true)
if err != nil {
log.Printf("Error starting user: %v", err)
}
if isUser {
msg = restartMsg
} else {
msg = startMsg
}
} else {
msg = alreadyStartedMsg
}
err = sendMsgWithMenu(u, msg)
if err != nil {
log.Printf("Error sending message to started user: %v", err)
}
}
func stopCmd(u *tb.User) {
admin, err := isBotAdmin(u.ID)
if err != nil {
log.Printf("Error checking if user is admin: %v", err)
}
if admin {
err := sendMsgWithMenu(u, unstoppableMsg)
if err != nil {
log.Printf("Error sending message to unstoppable user: %v", err)
}
} else {
err = startUser(u.ID, false)
if err != nil {
log.Printf("Error starting user: %v", err)
}
err := sendMsgWithSpecificMenu(u, stopMsg, startMenu)
if err != nil {
log.Printf("Error sending message to stopped user: %v", err)
}
}
}
func userInfoCmd(u *tb.User) {
userGroups, err := getUserGroups(u.ID)
if err != nil {
log.Printf("Error retriving user groups: %v", err)
}
stringGroups := convertUserGroups(userGroups)
isAdmin, err := isBotAdmin(u.ID)
if err != nil {
log.Printf("Error checking if user is admin: %v", err)
}
isAuth, err := isAuthrizedUser(u.ID)
if err != nil {
log.Printf("Error checking if user is authorized: %v", err)
}
msg := "\xF0\x9F\x91\xA4 *INFORMAZIONI UTENTE*" +
"\n- *Nome*: " + u.FirstName +
"\n- *Username*: " + u.Username +
"\n- *ID*: " + strconv.Itoa(u.ID) +
"\n- *Gruppi*: "
for _, group := range stringGroups {
msg += group + ", "
}
msg += "\n- *Tipo utente*: "
if isAdmin {
msg += "Admin"
} else if isAuth {
msg += "Autorizzato"
} else {
msg += "Utente semplice"
}
err = sendMsgWithSpecificMenu(u, msg, goBackMenu)
}

View File

@@ -1,78 +1,27 @@
package main
import (
"log"
"strconv"
tb "gopkg.in/tucnak/telebot.v2"
)
func startHandler(m *tb.Message) {
var msg string
isUser, err := isUser(m.Sender.ID)
if err != nil {
log.Printf("Error checking if ID is bot user: %v", err)
}
started, err := isStartedUser(m.Sender.ID)
if err != nil {
log.Printf("Error checking if user is started: %v", err)
}
if !started {
err = startUser(m.Sender.ID, true)
if err != nil {
log.Printf("Error starting user: %v", err)
}
if isUser {
msg = restartMsg
} else {
msg = startMsg
}
} else {
msg = alreadyStartedMsg
}
err = sendMsgWithMenu(m.Sender, msg)
if err != nil {
log.Printf("Error sending message to started user: %v", err)
}
}
func stopHandler(m *tb.Message) {
admin, err := isBotAdmin(m.Sender.ID)
if err != nil {
log.Printf("Error checking if user is admin: %v", err)
}
if admin {
msg := "Non ci siamo... Io l'ho nominata AMMINISTRATORE, cosa crede?! Questo ruolo esige impegno! Non può certo bloccarmi!"
err := sendMsg(m.Sender, msg)
if err != nil {
log.Printf("Error sending message to unstoppable user: %v", err)
}
} else {
err = startUser(m.Sender.ID, false)
if err != nil {
log.Printf("Error starting user: %v", err)
}
err := sendMsgWithSpecificMenu(m.Sender, stopMsg, startMenu)
if err != nil {
log.Printf("Error sending message to stopped user: %v", err)
}
}
}
func setBotHandlers() error {
if bot == nil {
return ErrNilPointer
}
bot.Handle("/start", startHandler)
bot.Handle("/stop", stopHandler)
bot.Handle("/menu", func(m *tb.Message) {
bot.Send(m.Sender, "hello world")
bot.Handle("/start", func(m *tb.Message) {
startCmd(m.Sender)
})
bot.Handle("/userID", func(m *tb.Message) {
bot.Send(m.Sender, strconv.Itoa(m.Sender.ID))
bot.Handle("/stop", func(m *tb.Message) {
stopCmd(m.Sender)
})
bot.Handle("/menu", func(m *tb.Message) {
sendMsgWithMenu(m.Sender, menuMsg)
})
bot.Handle("/userInfo", func(m *tb.Message) {
userInfoCmd(m.Sender)
})
bot.Handle("/botInfo", func(m *tb.Message) {
sendMsgWithSpecificMenu(m.Sender, contactMsg, goBackMenu)
})
return nil

View File

@@ -1,87 +0,0 @@
package main
import (
"log"
tb "gopkg.in/tucnak/telebot.v2"
)
var (
adminInlineMenu [][]tb.InlineButton
authInlineMenu [][]tb.InlineButton
genericInlineMenu [][]tb.InlineButton
startMenu [][]tb.InlineButton
)
var (
startBtn = tb.InlineButton{
Unique: "start_btn",
Text: "\xE2\x96\xB6 Avvia il barandaBot",
}
stopBtn = tb.InlineButton{
Unique: "stop_btn",
Text: "\xF0\x9F\x9A\xAB Ferma il barandaBot",
}
infoBtn = tb.InlineButton{
Unique: "info_btn",
Text: "\xE2\x84\xB9 Info",
}
)
func setBotMenus() error {
adminInlineMenu = append(adminInlineMenu, []tb.InlineButton{stopBtn, infoBtn})
authInlineMenu = append(authInlineMenu, []tb.InlineButton{stopBtn, infoBtn})
genericInlineMenu = append(genericInlineMenu, []tb.InlineButton{stopBtn, infoBtn})
startMenu = append(startMenu, []tb.InlineButton{startBtn})
return nil
}
func setBotCallbacks() error {
if bot == nil {
return ErrNilPointer
}
bot.Handle(&startBtn, func(c *tb.Callback) {
bot.Respond(c, &tb.CallbackResponse{})
//TODO: save last message id per user so it's possible to hide inline keyboard
//bot.Edit(lastMsgID, tb.ReplyMarkup{})
err := startUser(c.Sender.ID, true)
if err != nil {
log.Printf("Error starting user: %v", err)
}
err = sendMsgWithMenu(c.Sender, restartMsg)
if err != nil {
log.Printf("Error sending message to started user: %v", err)
}
})
bot.Handle(&stopBtn, func(c *tb.Callback) {
bot.Respond(c, &tb.CallbackResponse{})
admin, err := isBotAdmin(c.Sender.ID)
if err != nil {
log.Printf("Error checking if user is admin: %v", err)
}
if admin {
msg := "Non ci siamo... Io l'ho nominata AMMINISTRATORE, cosa crede?! Questo ruolo esige impegno! Non può certo bloccarmi!"
err := sendMsg(c.Sender, msg)
if err != nil {
log.Printf("Error sending message to unstoppable user: %v", err)
}
} else {
err = startUser(c.Sender.ID, false)
if err != nil {
log.Printf("Error starting user: %v", err)
}
err := sendMsgWithSpecificMenu(c.Sender, stopMsg, startMenu)
if err != nil {
log.Printf("Error sending message to stopped user: %v", err)
}
}
})
return nil
}

81
src/telegramMenus.go Normal file
View File

@@ -0,0 +1,81 @@
package main
import (
tb "gopkg.in/tucnak/telebot.v2"
)
var (
adminInlineMenu [][]tb.InlineButton
authInlineMenu [][]tb.InlineButton
genericInlineMenu [][]tb.InlineButton
startMenu [][]tb.InlineButton
goBackMenu [][]tb.InlineButton
)
var (
startBtn = tb.InlineButton{
Unique: "start_btn",
Text: "\xE2\x96\xB6 Avvia il barandaBot",
}
stopBtn = tb.InlineButton{
Unique: "stop_btn",
Text: "\xF0\x9F\x9A\xAB Ferma il barandaBot",
}
backBtn = tb.InlineButton{
Unique: "back_btn",
Text: "\xF0\x9F\x94\x99 Torna al menù principale",
}
infoBtn = tb.InlineButton{
Unique: "info_btn",
Text: "\xE2\x84\xB9 Info",
}
userBtn = tb.InlineButton{
Unique: "user_btn",
Text: "\xF0\x9F\x91\xA4 My info",
}
)
func setBotMenus() error {
genericInlineMenu = append(genericInlineMenu, []tb.InlineButton{userBtn, infoBtn}, []tb.InlineButton{stopBtn})
authInlineMenu = genericInlineMenu
adminInlineMenu = genericInlineMenu
//adminInlineMenu = append(adminInlineMenu, []tb.InlineButton{stopBtn, infoBtn})
//authInlineMenu = append(authInlineMenu, []tb.InlineButton{stopBtn, infoBtn})
startMenu = append(startMenu, []tb.InlineButton{startBtn})
goBackMenu = append(goBackMenu, []tb.InlineButton{backBtn})
return nil
}
func setBotCallbacks() error {
if bot == nil {
return ErrNilPointer
}
bot.Handle(&startBtn, func(c *tb.Callback) {
bot.Respond(c, &tb.CallbackResponse{})
startCmd(c.Sender)
})
bot.Handle(&stopBtn, func(c *tb.Callback) {
bot.Respond(c, &tb.CallbackResponse{})
stopCmd(c.Sender)
})
bot.Handle(&userBtn, func(c *tb.Callback) {
bot.Respond(c, &tb.CallbackResponse{})
userInfoCmd(c.Sender)
})
bot.Handle(&infoBtn, func(c *tb.Callback) {
bot.Respond(c, &tb.CallbackResponse{})
sendMsgWithSpecificMenu(c.Sender, contactMsg, goBackMenu)
})
bot.Handle(&backBtn, func(c *tb.Callback) {
bot.Respond(c, &tb.CallbackResponse{})
sendMsgWithMenu(c.Sender, menuMsg)
})
return nil
}