From 72c2bd05fa91ecb648b836fc93a292a715051581 Mon Sep 17 00:00:00 2001 From: maximo tejeda Date: Sun, 25 Feb 2024 21:23:23 -0400 Subject: [PATCH] ADD bot structure --- command/command.go | 165 +++++++++++++++++++++++++++++++++++++++++++++ helpers/helpers.go | 26 +++++++ query/query.go | 152 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 command/command.go create mode 100644 helpers/helpers.go create mode 100644 query/query.go diff --git a/command/command.go b/command/command.go new file mode 100644 index 0000000..ec49eba --- /dev/null +++ b/command/command.go @@ -0,0 +1,165 @@ +package commands + +import ( + "context" + "fmt" + "log/slog" + "slices" + "strings" + + tgbot "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "github.com/maximotejeda/us_dop_bot/db" + edb "github.com/maximotejeda/us_dop_bot/edb" + "github.com/maximotejeda/us_dop_bot/helpers" +) + +// CommandHandler +// Options for user to create queries on the bot +func CommandHandler(ctx context.Context, userDB *db.DB, instDB *edb.DB, log *slog.Logger, update tgbot.Update) tgbot.MessageConfig { + var ( + err error + msg tgbot.MessageConfig + usr = db.NewUser(userDB, log) + ) + command := update.Message.Command() + chatID := update.Message.Chat.ID + + msg.ChatID = chatID + + switch strings.ToLower(command) { + case "list", "lista": + msg, err = lista(update, userDB, instDB, log, "bancos") + if err != nil { + log.Error("command-status", "err", err) + } + case "listabancos": + msg, err = lista(update, userDB, instDB, log, "bancos") + if err != nil { + log.Error("command-status", "err", err) + } + case "listacajas": + msg, err = lista(update, userDB, instDB, log, "cajas") + if err != nil { + log.Error("command-status", "err", err) + } + + case "listagentes": + msg, err = lista(update, userDB, instDB, log, "agentes") + if err != nil { + log.Error("command-status", "err", err) + } + case "consulta": + _, err := usr.Get(update.Message.From.ID) + if err != nil { + log.Error("command-status", "err", err) + } + btnSTR := map[string]string{} + for _, inst := range usr.Subs { + switch inst { + case "asociacion popular de ahorros y prestamos": + btnSTR[inst] = "consultar=true&name=apap" + case "asociacion cibao de ahorros y prestamos": + btnSTR[inst] = "consultar=true&name=acap" + case "asociacion la nacional de ahorros y prestamos": + btnSTR[inst] = "consultar=true&name=anap" + default: + btnSTR[inst] = "consultar=true&name=" + inst + } + + } + btnSTR["cancelar ❌"] = "cancelar=true" + keyboard := helpers.CreateKeyboard(btnSTR) + msg.ReplyMarkup = keyboard + msg.Text = "Suscripciones actuales πŸ’°\nPuedes hacer click para Ver cambios en los precios de las suscripcion\n o presionar cancelar" + + case "status", "info": + _, err := usr.Get(update.Message.From.ID) + if err != nil { + log.Error("command-status", "err", err) + } + btnSTR := map[string]string{} + for _, inst := range usr.Subs { + btnSTR[inst] = "unsubs=true&name=" + inst + } + btnSTR["cancelar ❌"] = "cancelar=true" + keyboard := helpers.CreateKeyboard(btnSTR) + msg.ReplyMarkup = keyboard + msg.Text = "Suscripciones actuales πŸ’°\n Puedes hacer click en una para eliminar su subscripcion\nPresionar cancelar para omitir." + + case "reset": + reset := map[string]string{"Reset": "reset=true", "cancelar ❌": "cancelar=true"} + keyboard := helpers.CreateKeyboard(reset) + msg.ReplyMarkup = keyboard + msg.Text = "Elimina todas las suscripciones del usuario." + case "help", "start", "ayuda", "h": + + help := ` +Asistente de cambio US <-> DOP + πŸ‡ΊπŸ‡Έ ↔️ πŸ‡©πŸ‡΄ +Tracker del precio del dolar para RD. + +Funciona suscribiendo instituciones πŸ’Έ. + - Tracker precio del dolar ❇️. + - Notificacion mensaje automatico πŸ“ˆ. + - Precio actual ⌚. + - Historico de precios πŸ“…. + + Comandos Conocidos por el bot: + + /help: Muestra este mensaje ❓ + /listabancos: Muestra bancos 🏦 + /listacajas: Muestra asociaciones + /listagentes: Muestra agentes πŸ“Š + /consulta: Consulta entidad suscrita πŸ›ŽοΈ + /reset: Borra tada suscripcion 🧹 + /status: Estado del usuario πŸ“‹ +` + + msg.Text = help + default: + msg.Text = "Commando desconocido intenta con\n/help: to get bot info." + } + return msg +} + +func lista(update tgbot.Update, user *db.DB, insts *edb.DB, log *slog.Logger, instSTR string) (msg tgbot.MessageConfig, err error) { + var instList []string + usr := db.NewUser(user, log) + msg = tgbot.MessageConfig{} + msg.ChatID = update.Message.Chat.ID + _, err = usr.Get(update.Message.From.ID) + if err != nil { + log.Error("command-status", "err", err) + return msg, err + } + + // TODO list all institutions + + switch instSTR { + case "bancos": + instList, err = insts.GetBancos() + case "cajas": + instList, err = insts.GetCajas() + case "agentes": + instList, err = insts.GetAgentes() + default: + return msg, fmt.Errorf("tipio de institucion desconocida") + } + if err != nil { + log.Error("[inst-list-query]", "error", err) + return msg, err + } + instMap := map[string]string{} + for _, i := range instList { + if slices.Contains[[]string](usr.Subs, i) { + continue + } + instMap[i] = "subs=true&name=" + i + } + instMap["cancelar ❌"] = "cancelar=true" + keyboard := helpers.CreateKeyboard(instMap) + + msg.Text = "Differentes cajas disponibles para track el precio del cambio\n\n\tasociacion popular\n\n\tasociacion cibao\n\n" + msg.ReplyMarkup = keyboard + return msg, nil +} diff --git a/helpers/helpers.go b/helpers/helpers.go new file mode 100644 index 0000000..2700cb1 --- /dev/null +++ b/helpers/helpers.go @@ -0,0 +1,26 @@ +package helpers + +import tgb "github.com/go-telegram-bot-api/telegram-bot-api/v5" + +// CreateKeyboard +// create keybowrds of two rows of any map[string]string input +func CreateKeyboard(data map[string]string) tgb.InlineKeyboardMarkup { + // hardcoded models + keyboard := tgb.NewInlineKeyboardMarkup() + // subbuttons := []tgbot.InlineKeyboardButton{} + rows := tgb.NewInlineKeyboardRow() + counter := 0 + for key, val := range data { + + if counter != 0 && counter%3 == 0 { + keyboard.InlineKeyboard = append(keyboard.InlineKeyboard, rows) + rows = tgb.NewInlineKeyboardRow() + } + rows = append(rows, tgb.NewInlineKeyboardButtonData(key, val)) + if counter >= len(data)-1 { + keyboard.InlineKeyboard = append(keyboard.InlineKeyboard, rows) + } + counter++ + } + return keyboard +} diff --git a/query/query.go b/query/query.go new file mode 100644 index 0000000..2b7ef96 --- /dev/null +++ b/query/query.go @@ -0,0 +1,152 @@ +package query + +import ( + "context" + "fmt" + "log/slog" + "strconv" + "strings" + "time" + + tg "github.com/go-telegram-bot-api/telegram-bot-api/v5" + "github.com/maximotejeda/us_dop_bot/db" + edb "github.com/maximotejeda/us_dop_bot/edb" + "github.com/maximotejeda/us_dop_bot/helpers" + "github.com/maximotejeda/us_dop_bot/models" +) + +// QueryHandler +// Manage queries to execute user commands +func QueryHandler(ctx context.Context, dbx *db.DB, inst *edb.DB, log *slog.Logger, query *tg.CallbackQuery) (msg *tg.MessageConfig) { + tUser := query.From + user := db.NewUser(dbx, log) + _, err := user.Get(tUser.ID) + if err != nil { + log.Error("callback", "error", err) + } + data := query.Data + + dataList := strings.Split(data, "&") + + dataMap := map[string]string{} + for _, val := range dataList { + subData := strings.Split(val, "=") + dataMap[subData[0]] = subData[1] + } + + switch { + case dataMap["subs"] != "": + err := user.Subscribe(dataMap["name"]) + if err != nil { + log.Error("subs-query", "error", err.Error(), "user", user) + } + case dataMap["unsubs"] != "": + user.Get(tUser.ID) + err := user.Unsubscribe(dataMap["name"]) + if err != nil { + log.Error("unsubs-query", "error", err.Error()) + } + case dataMap["reset"] != "": + err := user.Reset() + if err != nil { + log.Error("[query reset] ", "error", err) + } + case dataMap["consultar"] != "": + name := "&name=" + dataMap["name"] + queryMap := map[string]string{ + "Actual": "query=true&time=0&unit=now" + name, + "30 Minutos": "query=true&time=30&unit=minute" + name, + "1 Hora": "query=true&time=1&unit=hour" + name, + "6 Horas": "query=true&time=6&unit=hour" + name, + "12 Horas": "query=true&time=12&unit=hour" + name, + "1 Dia": "query=true&time=24&unit=hour" + name, + "1 Semana": "query=true&time=168&unit=hour" + name, + "2 Semanas": "query=true&time=336&unit=hour" + name, + "1 Mes": "query=true&time=672&unit=hour" + name, + } + keyboard := helpers.CreateKeyboard(queryMap) + msg = &tg.MessageConfig{} + msg.ChatID = tUser.ID + msg.ReplyMarkup = keyboard + msg.Text = fmt.Sprintf("Intervalos de tiempo disponibles para consulta en %s el cambio del dolar desde hace:", dataMap["name"]) + case dataMap["query"] != "": + var timeUnit time.Duration + timeAmntSTR := dataMap["time"] + timeUnitSTR := dataMap["unit"] + name := dataMap["name"] + timeAmnt, err := strconv.Atoi(timeAmntSTR) + switch name { + case "apap": + name = "asociacion popular de ahorros y prestamos" + case "acap": + name = "asociacion cibao de ahorros y prestamos" + case "anap": + name = "asociacion la nacional de ahorros y prestamos" + } + if err != nil { + log.Error("[query-query] converting amount of time to int", "error", err) + return msg + } + switch timeUnitSTR { + case "minute": + timeUnit = time.Minute * time.Duration(timeAmnt) + instList, err := inst.GetChangeSince(name, timeUnit) + if err != nil { + log.Error("[GETLIST] querying the inst database minutes", "error", err) + return + } + queryMap := map[string]string{"clear": "cancel=true"} + keyboard := helpers.CreateKeyboard(queryMap) + msg = &tg.MessageConfig{} + msg.ChatID = tUser.ID + msg.ReplyMarkup = keyboard + + msg.Text = instMessage(instList) + + case "hour": + timeUnit = time.Hour * time.Duration(timeAmnt) + instList, err := inst.GetChangeSince(name, timeUnit) + if err != nil { + log.Error("[GETLIST] querying the inst database hours", "error", err) + return + } + queryMap := map[string]string{"clear": "cancel=true"} + keyboard := helpers.CreateKeyboard(queryMap) + msg = &tg.MessageConfig{} + msg.ChatID = tUser.ID + msg.ReplyMarkup = keyboard + + msg.Text = instMessage(instList) + case "now": + instRes, err := inst.GetLastPrice(name) + if err != nil { + log.Error("queriing the inst database now", "error", err) + return + } + queryMap := map[string]string{"clear": "cancel=true"} + keyboard := helpers.CreateKeyboard(queryMap) + msg = &tg.MessageConfig{} + msg.ChatID = tUser.ID + + msg.ReplyMarkup = keyboard + msg.Text = fmt.Sprintf("%s\nCompra: %.2f\nVenta: %.2f", instRes.Name, instRes.Compra, instRes.Venta) + + } + + //log.Info("", "time unit", timeUnit, "timeAmount", timeAmnt) + + } + return msg +} + +func instMessage(insts []*models.Institucion) string { + if len(insts) <= 0 { + return "Sin cambios registrados en este intervalo\nPrueba a ampliar el rango del tiempo deseado." + } + name := insts[0].Name + resultText := fmt.Sprintf("%s\n\n", name) + for _, i := range insts { + resultText = resultText + fmt.Sprintf(" %s\n Compra: %.2f Venta: %.2f\n", i.Parsed.Format(time.DateTime), i.Compra, i.Venta) + } + return resultText +}