Compare commits
34 Commits
f066e01d21
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e9e9702d5 | |||
| 6a6aff0274 | |||
| 615c479179 | |||
| 2e1dbbc6be | |||
| 7b892730f2 | |||
| edfdf4affb | |||
| ddca8c456f | |||
| 09fe5f2324 | |||
| 3f9447f0b8 | |||
| a35a5c8efc | |||
| ada1a97999 | |||
| d1f2c359a2 | |||
| c3d00b5dec | |||
| 12ffc3461f | |||
| f1f2ae721b | |||
| 4509aae6a8 | |||
| 11d3adf8db | |||
| 92634ce744 | |||
| 4ceb63a307 | |||
| 64345c9350 | |||
| b771745c47 | |||
| 9e6681da30 | |||
| bce61e698a | |||
| 823786c3ea | |||
| e3d2ba38a8 | |||
| e24c6813a7 | |||
| 871b6c6dcd | |||
| c52a1f7f40 | |||
| ff9a9ca154 | |||
| d6d2e06a72 | |||
| 87157b2081 | |||
| 01e132628c | |||
| 922e770405 | |||
| 695ecef4fd |
+6
-1
@@ -6,7 +6,12 @@ steps:
|
||||
- name: build
|
||||
image: golang
|
||||
commands:
|
||||
- go build -o valera_tg_bot main.go
|
||||
- go build -o valera_tg_bot cmd/valera/main.go
|
||||
|
||||
- name: test
|
||||
image: golang
|
||||
commands:
|
||||
- go test ./...
|
||||
|
||||
- name: scp
|
||||
image: appleboy/drone-scp
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"type": "go",
|
||||
"name": "run",
|
||||
"goExecPath": "/usr/local/go/bin/go",
|
||||
"buildParams": [
|
||||
"$PROJECT_DIR$/main.go",
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"valera/internal/config"
|
||||
"valera/internal/db"
|
||||
"valera/internal/states"
|
||||
"valera/internal/states/clear_bot_state"
|
||||
"valera/internal/states/eat_bot_state"
|
||||
"valera/internal/states/go_bot_state"
|
||||
"valera/internal/states/help_bot_state"
|
||||
"valera/internal/states/pause_bot_state"
|
||||
"valera/internal/states/ping_bot_state"
|
||||
"valera/internal/states/start_bot_state"
|
||||
"valera/internal/states/stat_bot_state"
|
||||
"valera/internal/states/weight_bot_state"
|
||||
|
||||
tgbot "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
)
|
||||
|
||||
const (
|
||||
version = "v1.9.0"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg := config.NewAppConfig()
|
||||
|
||||
bot, err := tgbot.NewBotAPI(cfg.TgConfig.Token)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
dataBase, err := db.NewDB(cfg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
u := tgbot.NewUpdate(0)
|
||||
u.Timeout = 60
|
||||
|
||||
updates, err := bot.GetUpdatesChan(u)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
botStates := []states.BotState{
|
||||
clear_bot_state.NewClearBotState(bot, dataBase),
|
||||
go_bot_state.NewGoBotState(bot, dataBase),
|
||||
stat_bot_state.NewStatBotState(bot, dataBase),
|
||||
start_bot_state.NewStartBotState(bot, dataBase, version),
|
||||
help_bot_state.NewHelpBotState(bot, dataBase),
|
||||
ping_bot_state.NewPingBotState(bot, dataBase),
|
||||
pause_bot_state.NewPauseBotState(bot, dataBase),
|
||||
eat_bot_state.NewEatBotState(bot, dataBase),
|
||||
weight_bot_state.NewWeightBotState(bot, dataBase),
|
||||
}
|
||||
|
||||
go func() {
|
||||
for _, s := range botStates {
|
||||
http.HandleFunc(s.GetHandler())
|
||||
}
|
||||
log.Println("Server is start up! port", cfg.Port)
|
||||
log.Fatal(http.ListenAndServe(cfg.Port, nil))
|
||||
}()
|
||||
|
||||
for update := range updates {
|
||||
|
||||
if update.Message == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
text := update.Message.Text
|
||||
chatID := update.Message.Chat.ID
|
||||
username := update.Message.From.UserName
|
||||
userInfoDTO, err := dataBase.GetChatInfo(chatID, username)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, s := range botStates {
|
||||
if err := s.Do(text, userInfoDTO); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package commands
|
||||
|
||||
type Command string
|
||||
|
||||
const (
|
||||
Start = Command("/start")
|
||||
Help = Command("/help")
|
||||
Ping = Command("/ping")
|
||||
Go = Command("/go")
|
||||
Stat = Command("/stat")
|
||||
Eat = Command("/eat")
|
||||
)
|
||||
@@ -1,19 +0,0 @@
|
||||
package config
|
||||
|
||||
type Config struct {
|
||||
MongoURL string
|
||||
DBName string
|
||||
ChatsCollectionName string
|
||||
WorkoutsCollectionName string
|
||||
CaloriesCollectionName string
|
||||
}
|
||||
|
||||
func NewConfig(mongoURl string, dbName string) *Config {
|
||||
return &Config{
|
||||
MongoURL: mongoURl,
|
||||
DBName: dbName,
|
||||
ChatsCollectionName: "chats",
|
||||
WorkoutsCollectionName: "workouts",
|
||||
CaloriesCollectionName: "calories",
|
||||
}
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
package db
|
||||
|
||||
const (
|
||||
UserStateNone = UserState("")
|
||||
UserStateGo = UserState("Go")
|
||||
UserStateEat = UserState("Eat")
|
||||
)
|
||||
|
||||
type UserState string
|
||||
|
||||
type Chat struct {
|
||||
ChatID int64 `bson:"chat_id"`
|
||||
}
|
||||
|
||||
type ChatInfo struct {
|
||||
ChatID int64 `bson:"chat_id"`
|
||||
Status string `bson:"status"`
|
||||
}
|
||||
|
||||
func (c *ChatInfo) GetStatus() UserState {
|
||||
return UserState(c.Status)
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"log"
|
||||
"time"
|
||||
"valera/config"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
cfg *config.Config
|
||||
}
|
||||
|
||||
func NewDB(
|
||||
mongoURL string,
|
||||
dbName string,
|
||||
) *DB {
|
||||
return &DB{
|
||||
cfg: config.NewConfig(mongoURL, dbName),
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DB) AddChat(chatID int64) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
client, err := mongo.Connect(ctx, options.Client().ApplyURI(db.cfg.MongoURL))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
collection := client.Database(db.cfg.DBName).Collection(db.cfg.ChatsCollectionName)
|
||||
|
||||
result := collection.FindOne(ctx, bson.M{"chat_id": chatID})
|
||||
if result.Err() == mongo.ErrNoDocuments {
|
||||
if _, err := collection.InsertOne(ctx, &Chat{ChatID: chatID}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return result.Err()
|
||||
}
|
||||
|
||||
func (db *DB) AddWorkout(chatID int64, workout *Workout) error {
|
||||
if workout.Count <= 0 {
|
||||
return nil
|
||||
}
|
||||
if err := db.AddChat(chatID); err != nil {
|
||||
return err
|
||||
}
|
||||
workout.ChatID = chatID
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
client, err := mongo.Connect(ctx, options.Client().ApplyURI(db.cfg.MongoURL))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
collection := client.Database(db.cfg.DBName).Collection(db.cfg.WorkoutsCollectionName)
|
||||
_, err = collection.InsertOne(
|
||||
ctx,
|
||||
workout,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) AddCalories(chatID int64, calories *Calories) error {
|
||||
if calories.Count <= 0 {
|
||||
return nil
|
||||
}
|
||||
if err := db.AddChat(chatID); err != nil {
|
||||
return err
|
||||
}
|
||||
calories.ChatID = chatID
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
client, err := mongo.Connect(ctx, options.Client().ApplyURI(db.cfg.MongoURL))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
collection := client.Database(db.cfg.DBName).Collection(db.cfg.CaloriesCollectionName)
|
||||
_, err = collection.InsertOne(
|
||||
ctx,
|
||||
calories,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) GetChatInfo(chatID int64) (*ChatInfo, error) {
|
||||
if err := db.AddChat(chatID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
client, err := mongo.Connect(ctx, options.Client().ApplyURI(db.cfg.MongoURL))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
collection := client.Database(db.cfg.DBName).Collection(db.cfg.ChatsCollectionName)
|
||||
chatInfoDTO := &ChatInfo{}
|
||||
if err := collection.FindOne(ctx, bson.M{"chat_id": chatID}).Decode(chatInfoDTO); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return chatInfoDTO, err
|
||||
}
|
||||
|
||||
func (db *DB) SetStatusToChat(chatID int64, status UserState) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
client, err := mongo.Connect(ctx, options.Client().ApplyURI(db.cfg.MongoURL))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
collection := client.Database(db.cfg.DBName).Collection(db.cfg.ChatsCollectionName)
|
||||
_, err = collection.UpdateOne(
|
||||
ctx,
|
||||
bson.M{"chat_id": chatID},
|
||||
bson.M{"$set": bson.M{"status": status}},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) GetStat(chatID int64) (map[string]int, error) {
|
||||
if err := db.AddChat(chatID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
client, err := mongo.Connect(ctx, options.Client().ApplyURI(db.cfg.MongoURL))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loc, _ := time.LoadLocation("Asia/Novosibirsk")
|
||||
t := time.Now().In(loc).Add(-24 * time.Hour)
|
||||
|
||||
res := map[string]int{}
|
||||
|
||||
collection := client.Database(db.cfg.DBName).Collection(db.cfg.WorkoutsCollectionName)
|
||||
cursor, err := collection.Find(
|
||||
ctx,
|
||||
bson.M{
|
||||
"chat_id": chatID,
|
||||
"created_at": bson.M{"$gt": t},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for cursor.Next(context.Background()) {
|
||||
var result Workout
|
||||
if err := cursor.Decode(&result); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
res[result.Name] += result.Count
|
||||
}
|
||||
if err := cursor.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
caloriesCollection := client.Database(db.cfg.DBName).Collection(db.cfg.CaloriesCollectionName)
|
||||
caloriesCursor, err := caloriesCollection.Find(
|
||||
ctx,
|
||||
bson.M{
|
||||
"chat_id": chatID,
|
||||
"created_at": bson.M{"$gt": t},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for caloriesCursor.Next(context.Background()) {
|
||||
var result Calories
|
||||
if err := caloriesCursor.Decode(&result); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
res["Калории"] += result.Count
|
||||
}
|
||||
if err := caloriesCursor.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (db *DB) GetAllChats() ([]int64, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
client, err := mongo.Connect(ctx, options.Client().ApplyURI(db.cfg.MongoURL))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
collection := client.Database(db.cfg.DBName).Collection(db.cfg.ChatsCollectionName)
|
||||
cursor, err := collection.Find(ctx, bson.M{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var res []int64
|
||||
for cursor.Next(context.Background()) {
|
||||
var result ChatInfo
|
||||
if err := cursor.Decode(&result); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
res = append(res, result.ChatID)
|
||||
}
|
||||
if err := cursor.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
module valera
|
||||
|
||||
go 1.17
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
||||
github.com/umputun/go-flags v1.5.1
|
||||
go.mongodb.org/mongo-driver v1.11.2
|
||||
)
|
||||
|
||||
@@ -19,6 +18,7 @@ require (
|
||||
github.com/xdg-go/stringprep v1.0.3 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
)
|
||||
|
||||
@@ -5,8 +5,8 @@ github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaEL
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
@@ -27,8 +27,6 @@ github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQ
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/umputun/go-flags v1.5.1 h1:vRauoXV3Ultt1HrxivSxowbintgZLJE+EcBy5ta3/mY=
|
||||
github.com/umputun/go-flags v1.5.1/go.mod h1:nTbvsO/hKqe7Utri/NoyN18GR3+EWf+9RrmsdwdhrEc=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
|
||||
@@ -41,6 +39,8 @@ go.mongodb.org/mongo-driver v1.11.2 h1:+1v2rDQUWNcGW7/7E0Jvdz51V38XXxJfhzbV17aNH
|
||||
go.mongodb.org/mongo-driver v1.11.2/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -52,7 +52,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AppConfig struct {
|
||||
Port string
|
||||
MongoConfig *MongoConfig
|
||||
TgConfig *TgConfig
|
||||
}
|
||||
|
||||
type MongoConfig struct {
|
||||
URL string
|
||||
DBName string
|
||||
ChatsCollectionName string
|
||||
WorkoutsCollectionName string
|
||||
CaloriesCollectionName string
|
||||
WeightCollectionName string
|
||||
}
|
||||
|
||||
type TgConfig struct {
|
||||
Token string
|
||||
}
|
||||
|
||||
func NewAppConfig() *AppConfig {
|
||||
mongoURL, err := readFile("mongo_url.txt")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
mongoURL = strings.ReplaceAll(mongoURL, "\n", "")
|
||||
|
||||
dbName, err := readFile("db_name.txt")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
dbName = strings.ReplaceAll(dbName, "\n", "")
|
||||
|
||||
token, err := readFile("token.txt")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
token = strings.ReplaceAll(token, "\n", "")
|
||||
|
||||
return &AppConfig{
|
||||
Port: ":10002",
|
||||
MongoConfig: &MongoConfig{
|
||||
URL: mongoURL,
|
||||
DBName: dbName,
|
||||
ChatsCollectionName: "chats",
|
||||
WorkoutsCollectionName: "workouts",
|
||||
CaloriesCollectionName: "calories",
|
||||
WeightCollectionName: "weights",
|
||||
},
|
||||
TgConfig: &TgConfig{
|
||||
Token: token,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func readFile(filename string) (string, error) {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
str := string(b)
|
||||
return str, nil
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package db
|
||||
|
||||
const (
|
||||
UserStateNone = UserState("")
|
||||
UserStateGo = UserState("Go")
|
||||
UserStateEat = UserState("Eat")
|
||||
UserStatePause = UserState("Pause")
|
||||
UserStateWeight = UserState("Weight")
|
||||
)
|
||||
|
||||
type UserState string
|
||||
|
||||
type Chat struct {
|
||||
ChatID int64 `bson:"chat_id"`
|
||||
}
|
||||
|
||||
type ChatInfo struct {
|
||||
ChatID int64 `bson:"chat_id"`
|
||||
Status string `bson:"status"`
|
||||
Username string `bson:"username"`
|
||||
}
|
||||
|
||||
func (c *ChatInfo) GetStatus() UserState {
|
||||
return UserState(c.Status)
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
"valera/internal/config"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
chatsColection *mongo.Collection
|
||||
workoutsColection *mongo.Collection
|
||||
caloriesColection *mongo.Collection
|
||||
weightColection *mongo.Collection
|
||||
}
|
||||
|
||||
func NewDB(
|
||||
cfg *config.AppConfig,
|
||||
) (*DB, error) {
|
||||
ctx := context.Background()
|
||||
opt := options.Client().
|
||||
ApplyURI(cfg.MongoConfig.URL).
|
||||
SetMinPoolSize(10)
|
||||
|
||||
client, err := mongo.Connect(ctx, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DB{
|
||||
chatsColection: client.Database(cfg.MongoConfig.DBName).Collection(cfg.MongoConfig.ChatsCollectionName),
|
||||
workoutsColection: client.Database(cfg.MongoConfig.DBName).Collection(cfg.MongoConfig.WorkoutsCollectionName),
|
||||
caloriesColection: client.Database(cfg.MongoConfig.DBName).Collection(cfg.MongoConfig.CaloriesCollectionName),
|
||||
weightColection: client.Database(cfg.MongoConfig.DBName).Collection(cfg.MongoConfig.WeightCollectionName),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (db *DB) AddChat(chatID int64) error {
|
||||
ctx := context.Background()
|
||||
|
||||
result := db.chatsColection.FindOne(ctx, bson.M{"chat_id": chatID})
|
||||
if result.Err() == mongo.ErrNoDocuments {
|
||||
if _, err := db.chatsColection.InsertOne(ctx, &Chat{ChatID: chatID}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if result.Err() != nil {
|
||||
return result.Err()
|
||||
}
|
||||
loc, _ := time.LoadLocation("Asia/Novosibirsk")
|
||||
t := time.Now().In(loc)
|
||||
_, err := db.chatsColection.UpdateOne(
|
||||
ctx,
|
||||
bson.M{"chat_id": chatID},
|
||||
bson.M{"$set": bson.M{"last_time": t}},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) AddWorkout(chatID int64, workout *Workout) error {
|
||||
ctx := context.Background()
|
||||
|
||||
if workout.Count <= 0 {
|
||||
return nil
|
||||
}
|
||||
if err := db.AddChat(chatID); err != nil {
|
||||
return err
|
||||
}
|
||||
workout.ChatID = chatID
|
||||
|
||||
_, err := db.workoutsColection.InsertOne(
|
||||
ctx,
|
||||
workout,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) AddCalories(chatID int64, calories *Calories) error {
|
||||
ctx := context.Background()
|
||||
|
||||
if err := db.AddChat(chatID); err != nil {
|
||||
return err
|
||||
}
|
||||
calories.ChatID = chatID
|
||||
|
||||
_, err := db.caloriesColection.InsertOne(
|
||||
ctx,
|
||||
calories,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) AddWeight(chatID int64, weight *Weight) error {
|
||||
ctx := context.Background()
|
||||
|
||||
if weight.Weight <= 0 {
|
||||
return nil
|
||||
}
|
||||
if err := db.AddChat(chatID); err != nil {
|
||||
return err
|
||||
}
|
||||
weight.ChatID = chatID
|
||||
|
||||
_, err := db.weightColection.InsertOne(
|
||||
ctx,
|
||||
weight,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) GetChatInfo(chatID int64, username string) (*ChatInfo, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
if err := db.AddChat(chatID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chatInfoDTO := &ChatInfo{Username: username}
|
||||
if err := db.chatsColection.FindOne(ctx, bson.M{"chat_id": chatID}).Decode(chatInfoDTO); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return chatInfoDTO, nil
|
||||
}
|
||||
|
||||
func (db *DB) SetStatusToChat(chatID int64, status UserState) error {
|
||||
ctx := context.Background()
|
||||
|
||||
_, err := db.chatsColection.UpdateOne(
|
||||
ctx,
|
||||
bson.M{"chat_id": chatID},
|
||||
bson.M{"$set": bson.M{"status": status}},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) SetPause(chatID int64, duration time.Duration) error {
|
||||
ctx := context.Background()
|
||||
|
||||
loc, _ := time.LoadLocation("Asia/Novosibirsk")
|
||||
t := time.Now().In(loc).Add(+duration)
|
||||
_, err := db.chatsColection.UpdateOne(
|
||||
ctx,
|
||||
bson.M{"chat_id": chatID},
|
||||
bson.M{"$set": bson.M{"pause_until": t}},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) GetStatBetween(chatID int64, startTime time.Time, endTime time.Time) (map[string]float64, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
if err := db.AddChat(chatID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := map[string]float64{}
|
||||
|
||||
cursor, err := db.workoutsColection.Find(
|
||||
ctx,
|
||||
bson.M{
|
||||
"chat_id": chatID,
|
||||
"created_at": bson.M{
|
||||
"$gte": startTime,
|
||||
"$lt": endTime,
|
||||
},
|
||||
},
|
||||
options.Find().SetSort(
|
||||
bson.M{
|
||||
"created_at": 1,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for cursor.Next(context.Background()) {
|
||||
var result Workout
|
||||
if err := cursor.Decode(&result); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
res[result.Name] += float64(result.Count)
|
||||
}
|
||||
if err := cursor.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
caloriesCursor, err := db.caloriesColection.Find(
|
||||
ctx,
|
||||
bson.M{
|
||||
"chat_id": chatID,
|
||||
"created_at": bson.M{
|
||||
"$gte": startTime,
|
||||
"$lt": endTime,
|
||||
},
|
||||
},
|
||||
options.Find().SetSort(
|
||||
bson.M{
|
||||
"created_at": 1,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for caloriesCursor.Next(context.Background()) {
|
||||
var result Calories
|
||||
if err := caloriesCursor.Decode(&result); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
res["Калории"] += float64(result.Count)
|
||||
}
|
||||
if err := caloriesCursor.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
weightCursor, err := db.weightColection.Find(
|
||||
ctx,
|
||||
bson.M{
|
||||
"chat_id": chatID,
|
||||
"created_at": bson.M{
|
||||
"$gte": startTime,
|
||||
"$lt": endTime,
|
||||
},
|
||||
},
|
||||
options.Find().SetSort(
|
||||
bson.M{
|
||||
"created_at": 1,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
firstWeight := 0.0
|
||||
lastWeight := 0.0
|
||||
countWeights := 0
|
||||
for weightCursor.Next(context.Background()) {
|
||||
var result Weight
|
||||
if err := weightCursor.Decode(&result); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
res["Вес кг"] = result.Weight
|
||||
if firstWeight == 0 {
|
||||
firstWeight = result.Weight
|
||||
}
|
||||
lastWeight = result.Weight
|
||||
countWeights++
|
||||
}
|
||||
if err := weightCursor.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if countWeights > 0 {
|
||||
res["Изменение веса"] = lastWeight - firstWeight
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (db *DB) GetAllChats() ([]int64, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
loc, _ := time.LoadLocation("Asia/Novosibirsk")
|
||||
t := time.Now().In(loc)
|
||||
cursor, err := db.chatsColection.Find(
|
||||
ctx,
|
||||
bson.M{
|
||||
"$or": bson.A{
|
||||
bson.M{
|
||||
"pause_until": bson.M{"$lt": t},
|
||||
},
|
||||
bson.M{
|
||||
"pause_until": bson.M{"$exists": false},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var res []int64
|
||||
for cursor.Next(context.Background()) {
|
||||
var result ChatInfo
|
||||
if err := cursor.Decode(&result); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
res = append(res, result.ChatID)
|
||||
}
|
||||
if err := cursor.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package db
|
||||
|
||||
import "time"
|
||||
|
||||
type Weight struct {
|
||||
ChatID int64 `bson:"chat_id"`
|
||||
Weight float64 `bson:"weight"`
|
||||
CreatedAt time.Time `bson:"created_at"`
|
||||
Username string `bson:"username"`
|
||||
}
|
||||
|
||||
func NewWeight(
|
||||
weight float64,
|
||||
username string,
|
||||
) *Weight {
|
||||
loc, _ := time.LoadLocation("Asia/Novosibirsk")
|
||||
return &Weight{
|
||||
Weight: weight,
|
||||
Username: username,
|
||||
CreatedAt: time.Now().In(loc),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package times
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
loc *time.Location
|
||||
)
|
||||
|
||||
func init() {
|
||||
loc, _ = time.LoadLocation("Asia/Novosibirsk")
|
||||
}
|
||||
|
||||
func GetNow() time.Time {
|
||||
t := time.Now().In(loc)
|
||||
return t
|
||||
}
|
||||
|
||||
func GetStartDay() time.Time {
|
||||
t := GetNow()
|
||||
t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, loc)
|
||||
return t
|
||||
}
|
||||
|
||||
func GetStartDayMinus(days int) time.Time {
|
||||
t := GetStartDay()
|
||||
for i := 0; i < days; i++ {
|
||||
t = t.Add(-24 * time.Hour)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func GetStartWeek() time.Time {
|
||||
t := GetStartDay()
|
||||
t = t.Add(-6 * 24 * time.Hour)
|
||||
return t
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package clear_bot_state
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
tgbot "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"valera/internal/db"
|
||||
"valera/internal/states"
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
"/c", // en
|
||||
"/с", // ru
|
||||
}
|
||||
|
||||
type clearBotState struct {
|
||||
bot *tgbot.BotAPI
|
||||
dataBase *db.DB
|
||||
}
|
||||
|
||||
func NewClearBotState(bot *tgbot.BotAPI, dataBase *db.DB) states.BotState {
|
||||
return &clearBotState{
|
||||
bot: bot,
|
||||
dataBase: dataBase,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *clearBotState) Do(text string, chatInfo *db.ChatInfo) error {
|
||||
if !slices.Contains(names, text) {
|
||||
return nil
|
||||
}
|
||||
|
||||
msg := tgbot.NewMessage(chatInfo.ChatID, "Чистка")
|
||||
msg.ReplyMarkup = tgbot.NewRemoveKeyboard(false)
|
||||
_, _ = s.bot.Send(msg)
|
||||
return s.dataBase.SetStatusToChat(chatInfo.ChatID, db.UserStateNone)
|
||||
}
|
||||
|
||||
func (s *clearBotState) GetHandler() (string, func(http.ResponseWriter, *http.Request)) {
|
||||
return names[0], func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package eat_bot_state
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
productsMap = map[string]struct {
|
||||
caloriesIn100G int
|
||||
awgWeightG int
|
||||
}{
|
||||
"чай": {caloriesIn100G: 65, awgWeightG: 200},
|
||||
"яблоко": {caloriesIn100G: 52, awgWeightG: 242},
|
||||
"хлеб": {caloriesIn100G: 245, awgWeightG: 35},
|
||||
"огурец": {caloriesIn100G: 15, awgWeightG: 20},
|
||||
"помидор": {caloriesIn100G: 18, awgWeightG: 18},
|
||||
"слива": {caloriesIn100G: 50, awgWeightG: 50},
|
||||
}
|
||||
)
|
||||
|
||||
func calcCalories(text string) (int, error) {
|
||||
product, ok := productsMap[strings.ToLower(text)]
|
||||
if ok {
|
||||
return product.caloriesIn100G * product.awgWeightG / 100, nil
|
||||
}
|
||||
arr := strings.Split(text, " ")
|
||||
if len(arr) == 2 {
|
||||
product, ok := productsMap[strings.ToLower(arr[0])]
|
||||
if ok {
|
||||
count, err := strconv.Atoi(arr[1])
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
return product.caloriesIn100G * count / 100, nil
|
||||
}
|
||||
count1, err := strconv.Atoi(arr[0])
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
count2, err := strconv.Atoi(arr[1])
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
return count1 * count2 / 100, nil
|
||||
}
|
||||
count, err := strconv.Atoi(text)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package eat_bot_state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCalcCalories(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
text string
|
||||
want int
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"empty text",
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"1 text",
|
||||
"1",
|
||||
1,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"2 5 text",
|
||||
"20 50",
|
||||
10,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"чай text",
|
||||
"чай",
|
||||
130,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"чай 250 text",
|
||||
"чай 250",
|
||||
162,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
count, err := calcCalories(tt.text)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("error calc calories: %v", err)
|
||||
return
|
||||
}
|
||||
if count != tt.want {
|
||||
fmt.Println(count, tt.want)
|
||||
fmt.Println(count, tt.want)
|
||||
t.Errorf("error count: %v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package eat_bot_state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
tgbot "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"valera/internal/db"
|
||||
"valera/internal/modules/times"
|
||||
"valera/internal/states"
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
"/eat",
|
||||
}
|
||||
|
||||
type eatBotState struct {
|
||||
bot *tgbot.BotAPI
|
||||
dataBase *db.DB
|
||||
}
|
||||
|
||||
func NewEatBotState(bot *tgbot.BotAPI, dataBase *db.DB) states.BotState {
|
||||
return &eatBotState{
|
||||
bot: bot,
|
||||
dataBase: dataBase,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *eatBotState) Do(text string, chatInfo *db.ChatInfo) error {
|
||||
if chatInfo.Status == string(db.UserStateEat) {
|
||||
count, err := calcCalories(text)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
if err := s.dataBase.AddCalories(chatInfo.ChatID, db.NewCalories(count, chatInfo.Username)); err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
stat, err := s.dataBase.GetStatBetween(chatInfo.ChatID, times.GetStartDay(), times.GetNow())
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
_, _ = s.bot.Send(tgbot.NewMessage(chatInfo.ChatID, fmt.Sprintf("Калории, фу, %d, записал.\nКалорий сегодня: %v", count, stat["Калории"])))
|
||||
return s.dataBase.SetStatusToChat(chatInfo.ChatID, db.UserStateNone)
|
||||
}
|
||||
|
||||
if !slices.Contains(names, text) {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, _ = s.bot.Send(tgbot.NewMessage(chatInfo.ChatID, "Вижу ты поел, отпишись сколько калорий было"))
|
||||
return s.dataBase.SetStatusToChat(chatInfo.ChatID, db.UserStateEat)
|
||||
}
|
||||
|
||||
func (s *eatBotState) GetHandler() (string, func(http.ResponseWriter, *http.Request)) {
|
||||
return names[0], func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package go_bot_state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
tgbot "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"valera/internal/db"
|
||||
"valera/internal/states"
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
"/go",
|
||||
"/го",
|
||||
}
|
||||
|
||||
var (
|
||||
workoutTypes = []string{
|
||||
"Приседания",
|
||||
"Тяга",
|
||||
"Бицепс",
|
||||
"Пресс",
|
||||
"Отжимания",
|
||||
"Подтягивания",
|
||||
}
|
||||
)
|
||||
|
||||
type goBotState struct {
|
||||
bot *tgbot.BotAPI
|
||||
dataBase *db.DB
|
||||
}
|
||||
|
||||
func NewGoBotState(bot *tgbot.BotAPI, dataBase *db.DB) states.BotState {
|
||||
return &goBotState{
|
||||
bot: bot,
|
||||
dataBase: dataBase,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *goBotState) Do(text string, chatInfo *db.ChatInfo) error {
|
||||
if chatInfo.Status == string(db.UserStateGo) {
|
||||
if err := s.dataBase.SetStatusToChat(chatInfo.ChatID, db.UserState(text)); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
msg := tgbot.NewMessage(chatInfo.ChatID, fmt.Sprintf("%s, отпишись сколько раз ты выполнил упражнение", text))
|
||||
msg.ReplyMarkup = tgbot.NewRemoveKeyboard(false)
|
||||
_, _ = s.bot.Send(msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
isWorkout := false
|
||||
for _, workoutType := range workoutTypes {
|
||||
if chatInfo.GetStatus() == db.UserState(workoutType) {
|
||||
count, err := strconv.Atoi(text)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
if err := s.dataBase.AddWorkout(chatInfo.ChatID, db.NewWorkout(workoutType, count, chatInfo.Username)); err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
msgText := fmt.Sprintf("Отлично, %s, записал.", text)
|
||||
if count <= 0 {
|
||||
msgText = "Плохо, хочешь быть толстым и не красивым?"
|
||||
}
|
||||
_, _ = s.bot.Send(tgbot.NewMessage(chatInfo.ChatID, msgText))
|
||||
if err := s.dataBase.SetStatusToChat(chatInfo.ChatID, db.UserStateNone); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
isWorkout = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if isWorkout {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !slices.Contains(names, text) {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.sendGoToChat(chatInfo.ChatID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *goBotState) GetHandler() (string, func(http.ResponseWriter, *http.Request)) {
|
||||
return names[0], func(w http.ResponseWriter, r *http.Request) {
|
||||
chats, err := s.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 {
|
||||
s.sendGoToChat(chatID)
|
||||
}
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = fmt.Fprintf(w, `{"result":"ok"}`)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *goBotState) sendGoToChat(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 := s.bot.Send(msg); err == nil {
|
||||
if err := s.dataBase.SetStatusToChat(chatID, db.UserStateGo); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package help_bot_state
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"valera/internal/db"
|
||||
"valera/internal/states"
|
||||
|
||||
tgbot "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
"/help",
|
||||
}
|
||||
|
||||
type helpBotState struct {
|
||||
bot *tgbot.BotAPI
|
||||
dataBase *db.DB
|
||||
}
|
||||
|
||||
func NewHelpBotState(bot *tgbot.BotAPI, dataBase *db.DB) states.BotState {
|
||||
return &helpBotState{
|
||||
bot: bot,
|
||||
dataBase: dataBase,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *helpBotState) Do(text string, chatInfo *db.ChatInfo) error {
|
||||
if !slices.Contains(names, text) {
|
||||
return nil
|
||||
}
|
||||
|
||||
msg := "Вот что я умею:\n\n1) Предлагать размяться\n - несколько видов упражнений 6 раз в день\n2) Показывать статистику за день\n3) Считать калории\n - введи одно число, я запишу калории\n - введи 2 числа через пробел одно количество грамм другое количество калорий в 100 граммах (порядок не важен), я посчитаю\n - введи название того что ты съел, я посчитаю (если знаю)"
|
||||
_, _ = s.bot.Send(tgbot.NewMessage(chatInfo.ChatID, msg))
|
||||
return s.dataBase.SetStatusToChat(chatInfo.ChatID, db.UserStateNone)
|
||||
}
|
||||
|
||||
func (s *helpBotState) GetHandler() (string, func(http.ResponseWriter, *http.Request)) {
|
||||
return names[0], func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package states
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"valera/internal/db"
|
||||
)
|
||||
|
||||
type BotState interface {
|
||||
Do(text string, chatInfo *db.ChatInfo) error
|
||||
GetHandler() (string, func(http.ResponseWriter, *http.Request))
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package pause_bot_state
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getDuration(text string) (time.Duration, error) {
|
||||
d := strings.TrimSuffix(text, "ч")
|
||||
d = strings.TrimSuffix(d, "д")
|
||||
count, err := strconv.Atoi(d)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
res := time.Duration(count) * time.Hour
|
||||
if strings.HasSuffix(text, "д") {
|
||||
res *= 24
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package pause_bot_state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
tgbot "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"valera/internal/db"
|
||||
"valera/internal/states"
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
"/pause",
|
||||
}
|
||||
|
||||
type pauseBotState struct {
|
||||
bot *tgbot.BotAPI
|
||||
dataBase *db.DB
|
||||
}
|
||||
|
||||
func NewPauseBotState(bot *tgbot.BotAPI, dataBase *db.DB) states.BotState {
|
||||
return &pauseBotState{
|
||||
bot: bot,
|
||||
dataBase: dataBase,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *pauseBotState) Do(text string, chatInfo *db.ChatInfo) error {
|
||||
if chatInfo.Status == string(db.UserStatePause) {
|
||||
duration, err := getDuration(text)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
if err := s.dataBase.SetPause(chatInfo.ChatID, duration); err != nil {
|
||||
return nil
|
||||
}
|
||||
msg := tgbot.NewMessage(chatInfo.ChatID, fmt.Sprintf("Поставил паузу %v, отдыхай", duration))
|
||||
msg.ReplyMarkup = tgbot.NewRemoveKeyboard(false)
|
||||
_, _ = s.bot.Send(msg)
|
||||
return s.dataBase.SetStatusToChat(chatInfo.ChatID, db.UserStateNone)
|
||||
}
|
||||
|
||||
if !slices.Contains(names, text) {
|
||||
return nil
|
||||
}
|
||||
|
||||
msg := tgbot.NewMessage(chatInfo.ChatID, "Хочешь отдохнуть? Сколько времени тебе нужно?")
|
||||
msg.ReplyMarkup = tgbot.NewReplyKeyboard([][]tgbot.KeyboardButton{
|
||||
tgbot.NewKeyboardButtonRow(
|
||||
tgbot.NewKeyboardButton("8ч"),
|
||||
tgbot.NewKeyboardButton("32ч"),
|
||||
),
|
||||
}...)
|
||||
_, _ = s.bot.Send(msg)
|
||||
return s.dataBase.SetStatusToChat(chatInfo.ChatID, db.UserStatePause)
|
||||
}
|
||||
|
||||
func (s *pauseBotState) GetHandler() (string, func(http.ResponseWriter, *http.Request)) {
|
||||
return names[0], func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package ping_bot_state
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
tgbot "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"valera/internal/db"
|
||||
"valera/internal/states"
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
"/ping",
|
||||
}
|
||||
|
||||
type pingBotState struct {
|
||||
bot *tgbot.BotAPI
|
||||
dataBase *db.DB
|
||||
}
|
||||
|
||||
func NewPingBotState(bot *tgbot.BotAPI, dataBase *db.DB) states.BotState {
|
||||
return &pingBotState{
|
||||
bot: bot,
|
||||
dataBase: dataBase,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *pingBotState) Do(text string, chatInfo *db.ChatInfo) error {
|
||||
if !slices.Contains(names, text) {
|
||||
return nil
|
||||
}
|
||||
|
||||
msg := "Понг"
|
||||
_, _ = s.bot.Send(tgbot.NewMessage(chatInfo.ChatID, msg))
|
||||
return s.dataBase.SetStatusToChat(chatInfo.ChatID, db.UserStateNone)
|
||||
}
|
||||
|
||||
func (s *pingBotState) GetHandler() (string, func(http.ResponseWriter, *http.Request)) {
|
||||
return names[0], func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package start_bot_state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"valera/internal/db"
|
||||
"valera/internal/states"
|
||||
|
||||
tgbot "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
"/start",
|
||||
}
|
||||
|
||||
type startBotState struct {
|
||||
bot *tgbot.BotAPI
|
||||
dataBase *db.DB
|
||||
version string
|
||||
}
|
||||
|
||||
func NewStartBotState(bot *tgbot.BotAPI, dataBase *db.DB, version string) states.BotState {
|
||||
return &startBotState{
|
||||
bot: bot,
|
||||
dataBase: dataBase,
|
||||
version: version,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *startBotState) Do(text string, chatInfo *db.ChatInfo) error {
|
||||
if !slices.Contains(names, text) {
|
||||
return nil
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("Здорова, я Валера (%s), твой тренер (%d).", s.version, chatInfo.ChatID)
|
||||
_, _ = s.bot.Send(tgbot.NewMessage(chatInfo.ChatID, msg))
|
||||
return s.dataBase.SetStatusToChat(chatInfo.ChatID, db.UserStateNone)
|
||||
}
|
||||
|
||||
func (s *startBotState) GetHandler() (string, func(http.ResponseWriter, *http.Request)) {
|
||||
return names[0], func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package stat_bot_state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
tgbot "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"valera/internal/db"
|
||||
"valera/internal/modules/times"
|
||||
"valera/internal/states"
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
"/stat",
|
||||
"/stat_week",
|
||||
}
|
||||
|
||||
type statBotState struct {
|
||||
bot *tgbot.BotAPI
|
||||
dataBase *db.DB
|
||||
}
|
||||
|
||||
func NewStatBotState(bot *tgbot.BotAPI, dataBase *db.DB) states.BotState {
|
||||
return &statBotState{
|
||||
bot: bot,
|
||||
dataBase: dataBase,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *statBotState) Do(text string, chatInfo *db.ChatInfo) error {
|
||||
if !slices.Contains(names, text) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if text == "/stat" {
|
||||
s.sendStatToChatAfter(chatInfo.ChatID, "Результаты за сегодня:\n", times.GetStartDay())
|
||||
}
|
||||
|
||||
if text == "/stat_week" {
|
||||
s.sendStatToChatAfter(chatInfo.ChatID, "Результаты за неделю:\n", times.GetStartWeek())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *statBotState) GetHandler() (string, func(http.ResponseWriter, *http.Request)) {
|
||||
return names[0], func(w http.ResponseWriter, r *http.Request) {
|
||||
chats, err := s.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 {
|
||||
t := times.GetStartDay()
|
||||
if err := s.sendStatToChatAfter(chatID, "Напоминаю:\n- Cегодня больше не жрем!\n\nРезультаты за сегодня:\n", times.GetStartDay()); err != nil {
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = fmt.Fprintf(w, `{"result":"error"}`)
|
||||
return
|
||||
}
|
||||
if t.Weekday() == time.Sunday {
|
||||
if err := s.sendStatToChatAfter(chatID, "Результаты за неделю:\n", times.GetStartWeek()); err != nil {
|
||||
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"}`)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *statBotState) sendStatToChatAfter(chatID int64, prefix string, t time.Time) error {
|
||||
msgText := prefix
|
||||
stat, err := s.dataBase.GetStatBetween(chatID, t, times.GetNow())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range stat {
|
||||
msgText += fmt.Sprintf("- %s: %v\n", k, v)
|
||||
}
|
||||
_, _ = s.bot.Send(tgbot.NewMessage(chatID, msgText))
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package weight_bot_state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
tgbot "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"valera/internal/db"
|
||||
"valera/internal/modules/times"
|
||||
"valera/internal/states"
|
||||
)
|
||||
|
||||
var names = []string{
|
||||
"/weight",
|
||||
}
|
||||
|
||||
type weightBotState struct {
|
||||
bot *tgbot.BotAPI
|
||||
dataBase *db.DB
|
||||
}
|
||||
|
||||
func NewWeightBotState(bot *tgbot.BotAPI, dataBase *db.DB) states.BotState {
|
||||
return &weightBotState{
|
||||
bot: bot,
|
||||
dataBase: dataBase,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *weightBotState) Do(text string, chatInfo *db.ChatInfo) error {
|
||||
if chatInfo.Status == string(db.UserStateWeight) {
|
||||
weight, err := getWeight(text)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
if weight <= 0 {
|
||||
_, _ = s.bot.Send(tgbot.NewMessage(chatInfo.ChatID, "Все фигня, давай по новой"))
|
||||
return nil
|
||||
}
|
||||
if err := s.dataBase.AddWeight(chatInfo.ChatID, db.NewWeight(weight, chatInfo.Username)); err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
stat, err := s.dataBase.GetStatBetween(chatInfo.ChatID, times.GetStartDayMinus(1), times.GetStartDay())
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
dWeight := 0.0
|
||||
if stat["Вес кг"] != 0 {
|
||||
dWeight = weight - stat["Вес кг"]
|
||||
}
|
||||
_, _ = s.bot.Send(tgbot.NewMessage(chatInfo.ChatID, fmt.Sprintf("%vкг, записал.\nИзменение веса: %vкг", weight, dWeight)))
|
||||
return s.dataBase.SetStatusToChat(chatInfo.ChatID, db.UserStateNone)
|
||||
}
|
||||
|
||||
if !slices.Contains(names, text) {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.sendWeightToChat(chatInfo.ChatID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *weightBotState) GetHandler() (string, func(http.ResponseWriter, *http.Request)) {
|
||||
return names[0], func(w http.ResponseWriter, r *http.Request) {
|
||||
chats, err := s.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 {
|
||||
s.sendWeightToChat(chatID)
|
||||
}
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = fmt.Fprintf(w, `{"result":"ok"}`)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *weightBotState) sendWeightToChat(chatID int64) {
|
||||
msg := tgbot.NewMessage(chatID, "Давай взвешивайся, отпишись сколько кг ты весишь")
|
||||
if _, err := s.bot.Send(msg); err == nil {
|
||||
if err := s.dataBase.SetStatusToChat(chatID, db.UserStateWeight); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getWeight(text string) (float64, error) {
|
||||
number := strings.ReplaceAll(text, ",", ".")
|
||||
return strconv.ParseFloat(number, 64)
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
tgbot "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"github.com/umputun/go-flags"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"valera/commands"
|
||||
"valera/db"
|
||||
)
|
||||
|
||||
const (
|
||||
version = "v1.3.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 := db.NewDB(
|
||||
mongoURL,
|
||||
dbName,
|
||||
)
|
||||
|
||||
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, r *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, r *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"); 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
|
||||
|
||||
userInfoDTO, err := dataBase.GetChatInfo(chatID)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
switch userInfoDTO.GetStatus() {
|
||||
case db.UserStateGo:
|
||||
count, err := strconv.Atoi(text)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
if err := dataBase.AddWorkout(chatID, db.NewWorkout("Отжимания", count, username)); err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
msgText := fmt.Sprintf("Отлично, %s, записал.", text)
|
||||
if count <= 0 {
|
||||
msgText = "Плохо, хочешь быть толстым и не красивым?"
|
||||
}
|
||||
msg := tgbot.NewMessage(chatID, msgText)
|
||||
msg.ReplyMarkup = tgbot.NewRemoveKeyboard(false)
|
||||
_, _ = bot.Send(msg)
|
||||
if err := dataBase.SetStatusToChat(chatID, db.UserStateNone); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
continue
|
||||
case db.UserStateEat:
|
||||
count, err := strconv.Atoi(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("Калории, фу, %s, записал.", text)))
|
||||
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) Предлагать размяться\n2) Показывать статистику\n3) Считать калории"))
|
||||
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, ""); 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sendGoToChat(bot *tgbot.BotAPI, dataBase *db.DB, chatID int64) {
|
||||
msg := tgbot.NewMessage(chatID, "Давай немного разомнемся, отжимания, отпишись сколько раз ты выполнил упражнение")
|
||||
msg.ReplyMarkup = tgbot.NewReplyKeyboard(
|
||||
tgbot.NewKeyboardButtonRow(
|
||||
tgbot.NewKeyboardButton("1"),
|
||||
tgbot.NewKeyboardButton("2"),
|
||||
tgbot.NewKeyboardButton("3"),
|
||||
tgbot.NewKeyboardButton("5"),
|
||||
tgbot.NewKeyboardButton("8"),
|
||||
),
|
||||
)
|
||||
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) error {
|
||||
stat, err := dataBase.GetStat(chatID)
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user