package main import ( "errors" "fmt" "io/ioutil" "log" "net/http" "os" "strconv" "strings" "valera/calories" "valera/commands" "valera/db" "valera/pause" tgbot "github.com/go-telegram-bot-api/telegram-bot-api" "github.com/umputun/go-flags" ) var ( workoutTypes = []string{ "Отжимания", "Пресс", "Подтягивания", "Приседания", } ) const ( version = "v1.6.0" ) type Opts struct { Token string `short:"t" long:"token" description:"Telegram api token"` Name string `short:"n" long:"name" description:"Telegram bot name" default:"@body_weight_loss_bot"` } var opts Opts func readFile(filename string) (string, error) { b, err := ioutil.ReadFile(filename) if err != nil { return "", err } str := string(b) return str, nil } func main() { run() } func run() { p := flags.NewParser(&opts, flags.PrintErrors|flags.PassDoubleDash|flags.HelpFlag) p.SubcommandsOptional = true if _, err := p.Parse(); err != nil { if err.(*flags.Error).Type != flags.ErrHelp { log.Println(errors.New("[ERROR] cli error: " + err.Error())) } os.Exit(2) } if opts.Token == "" { token, err := readFile("token.txt") if err != nil { panic(err) } opts.Token = strings.ReplaceAll(token, "\n", "") } fmt.Println(opts.Token) bot, err := tgbot.NewBotAPI(opts.Token) if err != nil { panic(err) } mongoURL, err := readFile("mongo_url.txt") if err != nil { panic(err) } mongoURL = strings.ReplaceAll(mongoURL, "\n", "") fmt.Println(mongoURL) dbName, err := readFile("db_name.txt") if err != nil { panic(err) } dbName = strings.ReplaceAll(dbName, "\n", "") fmt.Println(dbName) dataBase, err := db.NewDB( mongoURL, dbName, ) if err != nil { panic(err) } u := tgbot.NewUpdate(0) u.Timeout = 60 updates, err := bot.GetUpdatesChan(u) if err != nil { panic(err) } go func() { http.HandleFunc("/go", func(w http.ResponseWriter, _ *http.Request) { chats, err := dataBase.GetAllChats() if err != nil { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) _, _ = fmt.Fprintf(w, `{"result":"error"}`) return } for _, chatID := range chats { sendGoToChat(bot, dataBase, chatID) } w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) _, _ = fmt.Fprintf(w, `{"result":"ok"}`) }) http.HandleFunc("/stat", func(w http.ResponseWriter, _ *http.Request) { chats, err := dataBase.GetAllChats() if err != nil { fmt.Println(err) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) _, _ = fmt.Fprintf(w, `{"result":"error"}`) return } for _, chatID := range chats { if err := sendStatToChat(bot, dataBase, chatID, "Напоминаю:\n- Cегодня больше не жрем!\n\n", true); err != nil { fmt.Println(err) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) _, _ = fmt.Fprintf(w, `{"result":"error"}`) return } } w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) _, _ = fmt.Fprintf(w, `{"result":"ok"}`) }) port := ":10002" log.Println("Server is start up! port", port) log.Fatal(http.ListenAndServe(port, nil)) }() log.Println("Run", opts.Name) for update := range updates { if update.Message == nil { continue } text := update.Message.Text chatID := update.Message.Chat.ID username := update.Message.From.UserName if text == "/c" { msg := tgbot.NewMessage(chatID, "Чистка") msg.ReplyMarkup = tgbot.NewRemoveKeyboard(false) _, _ = bot.Send(msg) if err := dataBase.SetStatusToChat(chatID, db.UserStateNone); err != nil { log.Println(err) } continue } userInfoDTO, err := dataBase.GetChatInfo(chatID) if err != nil { log.Println(err) continue } isWorkout := false for _, workoutType := range workoutTypes { if userInfoDTO.GetStatus() == db.UserState(workoutType) { count, err := strconv.Atoi(text) if err != nil { log.Println(err) continue } if err := dataBase.AddWorkout(chatID, db.NewWorkout(workoutType, count, username)); err != nil { log.Println(err) continue } msgText := fmt.Sprintf("Отлично, %s, записал.", text) if count <= 0 { msgText = "Плохо, хочешь быть толстым и не красивым?" } _, _ = bot.Send(tgbot.NewMessage(chatID, msgText)) if err := dataBase.SetStatusToChat(chatID, db.UserStateNone); err != nil { log.Println(err) } isWorkout = true break } } if isWorkout { continue } switch userInfoDTO.GetStatus() { case db.UserStateGo: if err := dataBase.SetStatusToChat(chatID, db.UserState(text)); err != nil { log.Println(err) } msg := tgbot.NewMessage(chatID, fmt.Sprintf("%s, отпишись сколько раз ты выполнил упражнение", text)) msg.ReplyMarkup = tgbot.NewRemoveKeyboard(false) _, _ = bot.Send(msg) continue case db.UserStateEat: count, err := calories.CalcCalories(text) if err != nil { log.Println(err) continue } if err := dataBase.AddCalories(chatID, db.NewCalories(count, username)); err != nil { log.Println(err) continue } if count <= 0 { _, _ = bot.Send(tgbot.NewMessage(chatID, "Все фигня, давай по новой")) continue } _, _ = bot.Send(tgbot.NewMessage(chatID, fmt.Sprintf("Калории, фу, %d, записал.", count))) if err := dataBase.SetStatusToChat(chatID, db.UserStateNone); err != nil { log.Println(err) } continue case db.UserStatePause: duration, err := pause.GetDuration(text) if err != nil { log.Println(err) continue } if err := dataBase.SetPause(chatID, duration); err != nil { log.Println(err) } msg := tgbot.NewMessage(chatID, fmt.Sprintf("Поставил паузу %v, отдыхай", duration)) msg.ReplyMarkup = tgbot.NewRemoveKeyboard(false) _, _ = bot.Send(msg) if err := dataBase.SetStatusToChat(chatID, db.UserStateNone); err != nil { log.Println(err) } continue } command := commands.Command(strings.Replace(text, opts.Name, "", 1)) switch command { case commands.Start: _, _ = bot.Send(tgbot.NewMessage(chatID, fmt.Sprintf("Здорова, я Валера (%s), твой тренер (%d).", version, chatID))) if err := dataBase.SetStatusToChat(chatID, db.UserStateNone); err != nil { log.Println(err) } case commands.Help: _, _ = bot.Send(tgbot.NewMessage(chatID, "Вот что я умею:\n\n1) Предлагать размяться\n - несколько видов упражнений 6 раз в день\n2) Показывать статистику за день\n3) Считать калории\n - введи одно число, я запишу калории\n - введи 2 числа через пробел одно количество грамм другое количество калорий в 100 граммах (порядок не важен), я посчитаю\n - введи название того что ты съел, я посчитаю (если знаю)")) case commands.Ping: _, _ = bot.Send(tgbot.NewMessage(chatID, "pong")) case commands.Go: sendGoToChat(bot, dataBase, chatID) case commands.Stat: if err := sendStatToChat(bot, dataBase, chatID, "", false); err != nil { fmt.Println(err) continue } case commands.Eat: if _, err := bot.Send(tgbot.NewMessage(chatID, "Вижу ты поел, отпишись сколько калорий было")); err == nil { if err := dataBase.SetStatusToChat(chatID, db.UserStateEat); err != nil { log.Println(err) } } case commands.Pause: msg := tgbot.NewMessage(chatID, "Хочешь отдохнуть? Сколько времени тебе нужно?") msg.ReplyMarkup = tgbot.NewReplyKeyboard([][]tgbot.KeyboardButton{ tgbot.NewKeyboardButtonRow( tgbot.NewKeyboardButton("1ч"), tgbot.NewKeyboardButton("4ч"), ), tgbot.NewKeyboardButtonRow( tgbot.NewKeyboardButton("1д"), tgbot.NewKeyboardButton("2д"), tgbot.NewKeyboardButton("7д"), ), }...) if _, err := bot.Send(msg); err == nil { if err := dataBase.SetStatusToChat(chatID, db.UserStatePause); err != nil { log.Println(err) } } } } } func sendGoToChat(bot *tgbot.BotAPI, dataBase *db.DB, chatID int64) { msg := tgbot.NewMessage(chatID, "Давай немного разомнемся, выбирай:") rows := make([][]tgbot.KeyboardButton, 0, len(workoutTypes)) for _, workoutType := range workoutTypes { rows = append(rows, tgbot.NewKeyboardButtonRow(tgbot.NewKeyboardButton(workoutType))) } msg.ReplyMarkup = tgbot.NewReplyKeyboard(rows...) if _, err := bot.Send(msg); err == nil { if err := dataBase.SetStatusToChat(chatID, db.UserStateGo); err != nil { log.Println(err) } } } func sendStatToChat(bot *tgbot.BotAPI, dataBase *db.DB, chatID int64, prefix string, cron bool) error { stat, err := dataBase.GetStat(chatID, cron) if err != nil { return err } msgText := prefix + "Результаты за сегодня:\n" for k, v := range stat { msgText += fmt.Sprintf("- %s: %d\n", k, v) } _, _ = bot.Send(tgbot.NewMessage(chatID, msgText)) return nil }