Migration to Tongo, new logic for user storage #3
| @ -6,11 +6,10 @@ import ( | ||||
| 	"image" | ||||
| 	"image/color" | ||||
| 	"image/png" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"math/rand" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/fogleman/gg" | ||||
| ) | ||||
| @ -53,15 +52,14 @@ func initImage() *gg.Context { | ||||
| // На пустое изображение наносятся логотипы из списка, предварительно перемешанного. | ||||
| // К изображениям также добавляются порядковые номера (начиная с 1 вместо 0), | ||||
| // а правильный вариант возвращается вместе с итоговой картинкой | ||||
| func GenCaptcha() Captcha { | ||||
| func GenCaptcha() *Captcha { | ||||
| 	dc := initImage() | ||||
| 	rand.Seed(time.Now().UnixNano()) | ||||
| 	rand.Shuffle(len(Logos), func(i, j int) { Logos[i], Logos[j] = Logos[j], Logos[i] })                          // Перемешиваем логотипы | ||||
| 	rand.Shuffle(len(XPositions), func(i, j int) { XPositions[i], XPositions[j] = XPositions[j], XPositions[i] }) // И позиции | ||||
| 	correct_answer := 0 | ||||
| 	for i, logo := range Logos { | ||||
| 		x := XPositions[i] | ||||
| 		y := rand.Intn(ImageHeight - logo.Image.Bounds().Dy() - 30) | ||||
| 		y := rand.Intn(ImageHeight - logo.Image.Bounds().Dy() - 70) | ||||
| 		dc.DrawImage(logo.Image, x, y) | ||||
| 		if logo.IsCorrect { | ||||
| 			correct_answer = i + 1 | ||||
| @ -78,7 +76,7 @@ func GenCaptcha() Captcha { | ||||
| 		CorrectAnswer: correct_answer, | ||||
| 	} | ||||
|  | ||||
| 	return captcha | ||||
| 	return &captcha | ||||
| } | ||||
|  | ||||
| func (captcha *Captcha) ToReader() *bytes.Reader { | ||||
| @ -106,7 +104,7 @@ func (captcha *Captcha) ToBytes() (*[]byte, error) { | ||||
| // Логотипы читаются из папки /assets рядом с исполняемым файлом. | ||||
| // Принимается формат .png, логотип, представляющий правильный ответ называется godot.png | ||||
| func Init() error { | ||||
| 	files, err := ioutil.ReadDir("./assets") | ||||
| 	files, err := os.ReadDir("./assets") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| @ -1,20 +1,35 @@ | ||||
| package db | ||||
|  | ||||
| import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"git.nefrace.ru/nefrace/tongo" | ||||
| ) | ||||
|  | ||||
| type Chat struct { | ||||
| 	Id      int64 | ||||
| 	Title   string | ||||
| 	TopicId int64 `bson:"topic_id"` | ||||
| 	tongo.Item `bson:",inline"` | ||||
| 	ChatId     int64 `bson:"chat_id"` | ||||
| 	Title      string | ||||
| 	TopicId    int64  `bson:"topic_id"` | ||||
| 	Greet      string `bson:"greet"` | ||||
| } | ||||
|  | ||||
| func (Chat) Coll() string { return "chats" } | ||||
|  | ||||
| type User struct { | ||||
| 	Id             int64 | ||||
| 	ChatId         int64  `bson:"chat_id"` | ||||
| 	Username       string `bson:"username"` | ||||
| 	FirstName      string `bson:"first_name"` | ||||
| 	LastName       string `bson:"last_name"` | ||||
| 	CorrectAnswer  int8   `bson:"correct_answer"` | ||||
| 	CaptchaMessage int    `bson:"captcha_message"` | ||||
| 	IsBanned       bool   `bson:"is_banned"` | ||||
| 	DateJoined     int64  `bson:"date_joined"` | ||||
| 	JoinedMessage  int    `bson:"joined_message"` | ||||
| 	tongo.Item       `bson:",inline"` | ||||
| 	UserId           int64     `bson:"user_id"` | ||||
| 	ChatId           int64     `bson:"chat_id"` | ||||
| 	Username         string    `bson:"username"` | ||||
| 	FirstName        string    `bson:"first_name"` | ||||
| 	LastName         string    `bson:"last_name"` | ||||
| 	CorrectAnswer    int8      `bson:"correct_answer"` | ||||
| 	CaptchaMessage   int       `bson:"captcha_message"` | ||||
| 	IsJoined         bool      `bson:"is_joined"` | ||||
| 	DateJoined       time.Time `bson:"date_joined"` | ||||
| 	JoinedMessage    int       `bson:"joined_message"` | ||||
| 	LastNotification time.Time `bson:"last_notification"` | ||||
| 	Warnings         int       `bson:"warnings"` | ||||
| } | ||||
|  | ||||
| func (User) Coll() string { return "users" } | ||||
|  | ||||
| @ -15,7 +15,7 @@ services: | ||||
|     env_file: | ||||
|       - mongo.env | ||||
|     ports: | ||||
|       - 127.0.0.1:28002:27017 | ||||
|       - ${HOST}:28003:27017 | ||||
|     volumes: | ||||
|       - mongodata:/data/db | ||||
|       - mongoconfig:/data/configdb | ||||
| @ -24,7 +24,7 @@ services: | ||||
|     image: mongo-express | ||||
|     restart: always | ||||
|     ports: | ||||
|       - 127.0.0.1:8088:8081 | ||||
|       - ${HOST}:8090:8081 | ||||
|     env_file: | ||||
|       - mongo.env | ||||
|  | ||||
|  | ||||
							
								
								
									
										27
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								go.mod
									
									
									
									
									
								
							| @ -3,26 +3,31 @@ module kickerbot | ||||
| go 1.19 | ||||
|  | ||||
| require ( | ||||
| 	github.com/NicoNex/echotron/v3 v3.21.0 | ||||
| 	github.com/NicoNex/echotron/v3 v3.26.1 | ||||
| 	github.com/fogleman/gg v1.3.0 | ||||
| 	github.com/go-co-op/gocron v1.18.0 | ||||
| 	github.com/joho/godotenv v1.4.0 | ||||
| 	go.mongodb.org/mongo-driver v1.11.1 | ||||
| 	github.com/go-co-op/gocron v1.33.1 | ||||
| 	github.com/joho/godotenv v1.5.1 | ||||
| 	go.mongodb.org/mongo-driver v1.12.1 | ||||
| ) | ||||
|  | ||||
| require ( | ||||
| 	github.com/google/uuid v1.3.1 // indirect | ||||
| 	go.uber.org/atomic v1.11.0 // indirect | ||||
| ) | ||||
|  | ||||
| require ( | ||||
| 	git.nefrace.ru/nefrace/tongo v0.0.0-20230604223535-44cc124fb18a | ||||
| 	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect | ||||
| 	github.com/golang/snappy v0.0.4 // indirect | ||||
| 	github.com/klauspost/compress v1.15.13 // indirect | ||||
| 	github.com/montanaflynn/stats v0.6.6 // indirect | ||||
| 	github.com/pkg/errors v0.9.1 // indirect | ||||
| 	github.com/klauspost/compress v1.16.7 // indirect | ||||
| 	github.com/montanaflynn/stats v0.7.1 // indirect | ||||
| 	github.com/robfig/cron/v3 v3.0.1 // indirect | ||||
| 	github.com/xdg-go/pbkdf2 v1.0.0 // indirect | ||||
| 	github.com/xdg-go/scram v1.1.2 // indirect | ||||
| 	github.com/xdg-go/stringprep v1.0.4 // indirect | ||||
| 	github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect | ||||
| 	golang.org/x/crypto v0.4.0 // indirect | ||||
| 	golang.org/x/image v0.2.0 // indirect | ||||
| 	golang.org/x/sync v0.1.0 // indirect | ||||
| 	golang.org/x/text v0.5.0 // indirect | ||||
| 	golang.org/x/crypto v0.13.0 // indirect | ||||
| 	golang.org/x/image v0.12.0 // indirect | ||||
| 	golang.org/x/sync v0.3.0 // indirect | ||||
| 	golang.org/x/text v0.13.0 // indirect | ||||
| ) | ||||
|  | ||||
							
								
								
									
										91
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										91
									
								
								go.sum
									
									
									
									
									
								
							| @ -1,12 +1,15 @@ | ||||
| github.com/NicoNex/echotron/v3 v3.21.0 h1:6YDSYA/AGlPxWoUdOIRrBvUZ0RhRa2W4taS4eSrbdXw= | ||||
| github.com/NicoNex/echotron/v3 v3.21.0/go.mod h1:LpP5IyHw0y+DZUZMBgXEDAF9O8feXrQu7w7nlJzzoZI= | ||||
| git.nefrace.ru/nefrace/tongo v0.0.0-20230604223535-44cc124fb18a h1:rzWY7QiyuOMxTl6oMqkh2xi6m4KmNO2edZi8idmB57I= | ||||
| git.nefrace.ru/nefrace/tongo v0.0.0-20230604223535-44cc124fb18a/go.mod h1:QfvcElrkpZQAXeDzEEVh9fbViVFYS/ZOsn8Zvu6cTcg= | ||||
| github.com/NicoNex/echotron/v3 v3.26.1 h1:2I+jwvrMsbot+Di39Ro3k3XSiPJTtTh+fFOOiG4RzZI= | ||||
| github.com/NicoNex/echotron/v3 v3.26.1/go.mod h1:LpP5IyHw0y+DZUZMBgXEDAF9O8feXrQu7w7nlJzzoZI= | ||||
| github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | ||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= | ||||
| github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= | ||||
| github.com/go-co-op/gocron v1.18.0 h1:SxTyJ5xnSN4byCq7b10LmmszFdxQlSQJod8s3gbnXxA= | ||||
| github.com/go-co-op/gocron v1.18.0/go.mod h1:sD/a0Aadtw5CpflUJ/lpP9Vfdk979Wl1Sg33HPHg0FY= | ||||
| github.com/go-co-op/gocron v1.33.1 h1:wjX+Dg6Ae29a/f9BSQjY1Rl+jflTpW9aDyMqseCj78c= | ||||
| github.com/go-co-op/gocron v1.33.1/go.mod h1:NLi+bkm4rRSy1F8U7iacZOz0xPseMoIOnvabGoSe/no= | ||||
| github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= | ||||
| github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= | ||||
| github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | ||||
| @ -14,73 +17,73 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= | ||||
| github.com/golang/snappy v0.0.4/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/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= | ||||
| github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= | ||||
| github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= | ||||
| github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||
| github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= | ||||
| github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= | ||||
| github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= | ||||
| github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= | ||||
| github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= | ||||
| github.com/klauspost/compress v1.15.13 h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexDMMOV0= | ||||
| github.com/klauspost/compress v1.15.13/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= | ||||
| github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= | ||||
| github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= | ||||
| github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= | ||||
| github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | ||||
| github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= | ||||
| github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= | ||||
| github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||||
| github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= | ||||
| github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||||
| github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||||
| github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= | ||||
| github.com/montanaflynn/stats v0.6.6 h1:Duep6KMIDpY4Yo11iFsvyqJDyfzLF9+sndUKT+v64GQ= | ||||
| github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= | ||||
| github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||||
| github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= | ||||
| github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= | ||||
| github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= | ||||
| github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= | ||||
| github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= | ||||
| github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||
| github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= | ||||
| github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= | ||||
| github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= | ||||
| github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||||
| github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||
| github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||
| github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||||
| github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= | ||||
| github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | ||||
| 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= | ||||
| github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= | ||||
| github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= | ||||
| github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= | ||||
| github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= | ||||
| github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= | ||||
| github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= | ||||
| github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= | ||||
| github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= | ||||
| github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= | ||||
| github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= | ||||
| github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | ||||
| go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE= | ||||
| go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= | ||||
| go.mongodb.org/mongo-driver v1.11.1 h1:QP0znIRTuL0jf1oBQoAoM0C6ZJfBK4kx0Uumtv1A7w8= | ||||
| go.mongodb.org/mongo-driver v1.11.1/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= | ||||
| go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE= | ||||
| go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= | ||||
| go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= | ||||
| go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= | ||||
| go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= | ||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||
| golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||||
| golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | ||||
| golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= | ||||
| golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= | ||||
| golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= | ||||
| golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= | ||||
| golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk= | ||||
| golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c= | ||||
| golang.org/x/image v0.2.0 h1:/DcQ0w3VHKCC5p0/P2B0JpAZ9Z++V2KOo2fyU89CXBQ= | ||||
| golang.org/x/image v0.2.0/go.mod h1:la7oBXb9w3YFjBqaAwtynVioc1ZvOnNteUNrifGNmAI= | ||||
| golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= | ||||
| golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= | ||||
| golang.org/x/image v0.12.0 h1:w13vZbU4o5rKOFFR8y7M+c4A5jXDC0uXTdHYRP8X2DQ= | ||||
| golang.org/x/image v0.12.0/go.mod h1:Lu90jvHG7GfemOIcldsh9A2hS01ocl6oNO7ype5mEnk= | ||||
| golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||||
| golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | ||||
| golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
| golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||||
| golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||||
| golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||||
| golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= | ||||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= | ||||
| golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= | ||||
| golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= | ||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| @ -88,25 +91,29 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w | ||||
| golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||||
| golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||||
| golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= | ||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||
| golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||
| golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||||
| golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= | ||||
| golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= | ||||
| golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | ||||
| golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= | ||||
| golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | ||||
| golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | ||||
| golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= | ||||
| golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= | ||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||
| golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | ||||
| golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= | ||||
| golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| 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= | ||||
| gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= | ||||
| gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= | ||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
|  | ||||
| @ -2,6 +2,7 @@ package kicker | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"kickerbot/captchagen" | ||||
| 	"kickerbot/db" | ||||
| @ -9,84 +10,119 @@ import ( | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	tb "github.com/NicoNex/echotron/v3" | ||||
| 	"go.mongodb.org/mongo-driver/bson" | ||||
| 	"git.nefrace.ru/nefrace/tongo" | ||||
| 	"github.com/NicoNex/echotron/v3" | ||||
| 	"go.mongodb.org/mongo-driver/mongo" | ||||
| ) | ||||
|  | ||||
| func userJoined(b *bot, update *tb.Update) error { | ||||
| 	captcha := captchagen.GenCaptcha() | ||||
| 	_, err := b.DeleteMessage(update.Message.Chat.ID, update.Message.ID) | ||||
| func userJoined(b *bot, update *echotron.Update) error { | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) | ||||
| 	defer cancel() | ||||
| 	store := tongo.NewStore[db.User](Client) | ||||
| 	usr := update.Message.NewChatMembers[0] | ||||
| 	message := update.Message | ||||
| 	user, err := store.GetOne(ctx, tongo.E("chat_id", update.ChatID()), tongo.E("user_id", usr.ID)) | ||||
| 	var captcha *captchagen.Captcha | ||||
| 	if err != nil { | ||||
| 		log.Printf("Can't delete message: %v", err) | ||||
| 		if errors.Is(err, mongo.ErrNoDocuments) { | ||||
| 			captcha = captchagen.GenCaptcha() | ||||
| 			user = &db.User{ | ||||
| 				Item:             tongo.NewID(), | ||||
| 				UserId:           usr.ID, | ||||
| 				Username:         usr.Username, | ||||
| 				FirstName:        usr.FirstName, | ||||
| 				LastName:         usr.LastName, | ||||
| 				IsJoined:         false, | ||||
| 				ChatId:           message.Chat.ID, | ||||
| 				JoinedMessage:    message.ID, | ||||
| 				CorrectAnswer:    int8(captcha.CorrectAnswer), | ||||
| 				DateJoined:       time.Now(), | ||||
| 				LastNotification: time.Now(), | ||||
| 			} | ||||
| 		} else { | ||||
| 			log.Printf("Can't find user: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 	if captcha == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	// _, err := b.DeleteMessage(update.Message.Chat.ID, update.Message.ID) | ||||
| 	// if err != nil { | ||||
| 	// 	log.Printf("Can't delete message: %v", err) | ||||
| 	// } | ||||
| 	bytes, err := captcha.ToBytes() | ||||
| 	if err != nil { | ||||
| 		log.Printf("Error creating captcha bytes: %v", bytes) | ||||
| 		b.SendMessage("Не могу создать капчу, @nefrace, проверь логи.", update.Message.From.ID, &tb.MessageOptions{MessageThreadID: update.Message.ThreadID}) | ||||
| 		b.SendMessage("Не могу создать капчу, @nefrace, проверь логи.", update.Message.Chat.ID, &echotron.MessageOptions{MessageThreadID: int64(update.Message.ThreadID)}) | ||||
| 	} | ||||
| 	message := update.Message | ||||
| 	user := db.User{ | ||||
| 		Id:            message.From.ID, | ||||
| 		Username:      message.From.Username, | ||||
| 		FirstName:     message.From.FirstName, | ||||
| 		LastName:      message.From.LastName, | ||||
| 		IsBanned:      false, | ||||
| 		ChatId:        message.Chat.ID, | ||||
| 		JoinedMessage: message.ID, | ||||
| 		CorrectAnswer: int8(captcha.CorrectAnswer), | ||||
| 		DateJoined:    time.Now().Unix(), | ||||
| 	} | ||||
| 	user.CorrectAnswer = int8(captcha.CorrectAnswer) | ||||
| 	d := db.GetDatabase() | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) | ||||
| 	defer cancel() | ||||
| 	log.Print(user) | ||||
| 	msg := fmt.Sprintf("Приветствую тебя, *[%s](tg://user?id=%d)*\\!\nДля подтверждения, что ты человек, выбери логотип движка, которому посвящен данный чат, и отправь его номер сюда\\.\n*_Я дам тебе две минуты на это\\._*", EscapeText(tb.MarkdownV2, user.FirstName), user.Id) | ||||
| 	options := tb.PhotoOptions{ | ||||
| 	msg := fmt.Sprintf("Приветствую тебя, *%s*\\!\nДля подтверждения, что ты человек, выбери логотип движка, которому посвящен данный чат, и отправь его номер сюда\\.\n*_Я дам тебе десять минут на это\\._*", UserMention(usr)) | ||||
| 	options := echotron.PhotoOptions{ | ||||
| 		Caption:   msg, | ||||
| 		ParseMode: tb.MarkdownV2, | ||||
| 		ParseMode: echotron.MarkdownV2, | ||||
| 	} | ||||
| 	if message.Chat.IsForum { | ||||
| 		options.MessageThreadID = int(b.CaptchaTopic) | ||||
| 	} | ||||
| 	result, err := b.SendPhoto(tb.NewInputFileBytes("logos.png", *bytes), message.Chat.ID, &options) | ||||
| 	result, err := b.SendPhoto(echotron.NewInputFileBytes("logos.png", *bytes), message.Chat.ID, &options) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	user.CaptchaMessage = result.Result.ID | ||||
|  | ||||
| 	d.NewUser(ctx, user) | ||||
| 	store.InsertOne(ctx, user) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func userLeft(b *bot, update *tb.Update) error { | ||||
| func userLeft(b *bot, update *echotron.Update) error { | ||||
| 	message := update.Message | ||||
| 	sender := message.From | ||||
| 	d := db.GetDatabase() | ||||
| 	store := tongo.NewStore[db.User](Client) | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) | ||||
| 	defer cancel() | ||||
| 	if user, err := d.GetUser(ctx, db.User{Id: sender.ID, ChatId: message.Chat.ID}); err == nil { | ||||
| 		d.RemoveUser(ctx, user) | ||||
| 	if user, err := store.GetOne(ctx, tongo.E("user_id", sender.ID), tongo.E("chat_id", message.Chat.ID), tongo.E("is_joined", false)); err == nil { //d.GetUser(ctx, db.User{UserId: sender.ID, ChatId: message.Chat.ID}); err == nil { | ||||
| 		store.DeleteByID(ctx, user.Id) | ||||
| 		b.DeleteMessage(message.Chat.ID, message.ID) | ||||
| 		b.DeleteMessage(message.Chat.ID, user.CaptchaMessage) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func checkCaptcha(b *bot, update *tb.Update) error { | ||||
| 	message := update.Message | ||||
| 	sender := message.From | ||||
| 	d := db.GetDatabase() | ||||
| func userBanned(b *bot, update *echotron.Update) error { | ||||
| 	m := update.ChatMember | ||||
| 	c := m.Chat | ||||
| 	u := m.NewChatMember.User | ||||
| 	store := tongo.NewStore[db.User](Client) | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) | ||||
| 	defer cancel() | ||||
| 	if user, err := d.GetUser(ctx, db.User{Id: sender.ID, ChatId: message.Chat.ID}); err == nil { | ||||
| 	if user, err := store.GetOne(ctx, tongo.E("user_id", u.ID), tongo.E("chat_id", c.ID)); err == nil { //d.GetUser(ctx, db.User{UserId: sender.ID, ChatId: message.Chat.ID}); err == nil { | ||||
| 		store.DeleteByID(ctx, user.Id) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func checkCaptcha(b *bot, update *echotron.Update) error { | ||||
| 	message := update.Message | ||||
| 	sender := message.From | ||||
| 	store := tongo.NewStore[db.User](Client) | ||||
| 	chatStore := tongo.NewStore[db.Chat](Client) | ||||
| 	// d := db.GetDatabase() | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) | ||||
| 	defer cancel() | ||||
|  | ||||
| 	if user, err := store.GetOne(ctx, | ||||
| 		tongo.E("user_id", sender.ID), | ||||
| 		tongo.E("chat_id", message.Chat.ID), | ||||
| 		tongo.E("is_joined", false), | ||||
| 	); err == nil { //d.GetUser(ctx, db.User{UserId: sender.ID, ChatId: message.Chat.ID}); err == nil { | ||||
| 		chat, err := chatStore.GetOne(ctx, tongo.E("chat_id", message.Chat.ID)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if message.Chat.IsForum { | ||||
| 			chat, err := d.GetChat(ctx, message.Chat.ID) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if message.ThreadID != int(chat.TopicId) { | ||||
| 				b.DeleteMessage(message.Chat.ID, message.ID) | ||||
| 				text := fmt.Sprintf("*%s*, сначала пройди капчу\\!", UserMention(sender)) | ||||
| 				res, _ := b.SendMessage(text, message.Chat.ID, &echotron.MessageOptions{ParseMode: echotron.MarkdownV2, MessageThreadID: int64(message.ThreadID)}) | ||||
| 				go waitAndDelete(&b.API, res.Result, 10*time.Second) | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| @ -95,23 +131,30 @@ func checkCaptcha(b *bot, update *tb.Update) error { | ||||
| 		solved := false | ||||
| 		if num, err := strconv.Atoi(guess); err == nil { | ||||
| 			if num == int(user.CorrectAnswer) { | ||||
| 				_ = d.RemoveUser(ctx, user) | ||||
| 				user.IsJoined = true | ||||
| 				store.ReplaceItem(ctx, *user, true) | ||||
| 				solved = true | ||||
| 				b.DeleteMessage(message.Chat.ID, message.ID) | ||||
| 				b.DeleteMessage(message.Chat.ID, user.CaptchaMessage) | ||||
| 				msg := fmt.Sprintf("*[%s](tg://user?id=%d)* только что успешно прошёл капчу\\!", EscapeText(tb.MarkdownV2, user.FirstName), user.Id) | ||||
| 				options := tb.MessageOptions{ | ||||
| 					ParseMode: tb.MarkdownV2, | ||||
| 				msg := fmt.Sprintf("Капча успешно пройдена пользователем *%s*", UserMention(sender)) | ||||
| 				timeout := 10 * time.Second | ||||
| 				if chat.Greet != "" { | ||||
| 					msg = fmt.Sprintf(chat.Greet, UserMention(sender)) | ||||
| 					timeout = 2 * time.Minute | ||||
| 				} | ||||
| 				options := echotron.MessageOptions{ | ||||
| 					ParseMode: echotron.MarkdownV2, | ||||
| 				} | ||||
| 				if message.Chat.IsForum { | ||||
| 					options.MessageThreadID = int(b.CaptchaTopic) | ||||
| 					options.MessageThreadID = b.CaptchaTopic | ||||
| 				} | ||||
| 				res, err := b.SendMessage(msg, message.Chat.ID, &options) | ||||
| 				if err != nil { | ||||
| 					log.Printf("Can't send welcome message: %s", err) | ||||
| 				} | ||||
| 				time.Sleep(time.Second * 10) | ||||
| 				_, err = b.DeleteMessage(message.Chat.ID, res.Result.ID) | ||||
| 				go waitAndDelete(&b.API, res.Result, timeout*time.Second) | ||||
| 				// time.Sleep(time.Second * 10) | ||||
| 				// _, err = b.DeleteMessage(message.Chat.ID, res.Result.ID) | ||||
| 				if err != nil { | ||||
| 					log.Printf("Can't delete welcome message: %s", err) | ||||
| 				} | ||||
| @ -122,45 +165,57 @@ func checkCaptcha(b *bot, update *tb.Update) error { | ||||
| 			b.DeleteMessage(message.Chat.ID, user.CaptchaMessage) | ||||
| 			b.DeleteMessage(message.Chat.ID, user.JoinedMessage) | ||||
| 			b.BanChatMember(message.Chat.ID, sender.ID, nil) | ||||
| 			_ = d.RemoveUser(ctx, user) | ||||
| 			store.DeleteByID(ctx, user.Id) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func botAdded(b *bot, update *tb.Update) error { | ||||
| func botAdded(b *bot, update *echotron.Update) error { | ||||
| 	m := update.Message | ||||
| 	chat := db.Chat{ | ||||
| 		Id:      m.Chat.ID, | ||||
| 		Title:   m.Chat.Title, | ||||
| 		TopicId: 0, | ||||
| 	} | ||||
| 	store := tongo.NewStore[db.Chat](Client) | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) | ||||
| 	defer cancel() | ||||
| 	d := db.GetDatabase() | ||||
| 	err := d.NewChat(ctx, chat) | ||||
| 	chat, err := store.GetOne(ctx, tongo.E("chat_id", m.Chat.ID)) | ||||
| 	if err != nil { | ||||
| 		chat = &db.Chat{ | ||||
| 			Item:    tongo.NewID(), | ||||
| 			ChatId:  m.Chat.ID, | ||||
| 			Title:   m.Chat.Title, | ||||
| 			TopicId: 0, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	_, err = store.InsertOne(ctx, chat) | ||||
| 	if err != nil { | ||||
| 		log.Print(err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func setTopic(b *bot, update *tb.Update) error { | ||||
| func setTopic(b *bot, update *echotron.Update) error { | ||||
| 	m := update.Message | ||||
| 	d := db.GetDatabase() | ||||
| 	if res, err := b.GetChatMember(m.Chat.ID, m.From.ID); err == nil { | ||||
| 		m := res.Result | ||||
| 		if !(m.Status == "administrator" || m.Status == "creator") { | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||||
| 	defer cancel() | ||||
| 	chat, err := d.GetChat(ctx, m.Chat.ID) | ||||
| 	store := tongo.NewStore[db.Chat](Client) | ||||
| 	chat, err := store.GetOne(ctx, tongo.E("chat_id", m.Chat.ID)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	upd := bson.D{{Key: "$set", Value: bson.D{{Key: "topic_id", Value: m.ThreadID}}}} | ||||
| 	chat.TopicId = int64(m.ThreadID) | ||||
| 	// upd := bson.D{{Key: "$set", Value: bson.D{{Key: "topic_id", Value: m.ThreadID}}}} | ||||
| 	b.CaptchaTopic = int64(m.ThreadID) | ||||
| 	err = d.UpdateChat(ctx, chat, upd) | ||||
| 	err = store.ReplaceItem(ctx, *chat, false) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	b.DeleteMessage(m.Chat.ID, m.ID) | ||||
| 	b.SendMessage("Данный топик выбран в качестве проверочного для пользователей", m.Chat.ID, &tb.MessageOptions{MessageThreadID: m.ThreadID}) | ||||
| 	b.SendMessage("Данный топик выбран в качестве проверочного для пользователей", m.Chat.ID, &echotron.MessageOptions{MessageThreadID: int64(m.ThreadID)}) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @ -2,22 +2,27 @@ package kicker | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"kickerbot/db" | ||||
| 	"log" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	tb "github.com/NicoNex/echotron/v3" | ||||
| 	"git.nefrace.ru/nefrace/tongo" | ||||
| 	"github.com/NicoNex/echotron/v3" | ||||
| ) | ||||
|  | ||||
| var Client *tongo.Database | ||||
|  | ||||
| type bot struct { | ||||
| 	chatID       int64 | ||||
| 	CaptchaTopic int64 | ||||
| 	Me           *tb.User | ||||
| 	tb.API | ||||
| 	Me           *echotron.User | ||||
| 	echotron.API | ||||
| } | ||||
|  | ||||
| func (b *bot) Update(update *tb.Update) { | ||||
| func (b *bot) Update(update *echotron.Update) { | ||||
| 	if update.Message != nil { | ||||
| 		if len(update.Message.NewChatMembers) != 0 { | ||||
| 			for _, user := range update.Message.NewChatMembers { | ||||
| @ -40,36 +45,46 @@ func (b *bot) Update(update *tb.Update) { | ||||
| 			checkCaptcha(b, update) | ||||
| 		} | ||||
| 	} | ||||
| 	if update.ChatMember != nil { | ||||
| 		m := update.ChatMember.NewChatMember | ||||
| 		if m.Status == "kicked" { | ||||
| 			userBanned(b, update) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Базовая структура для бота | ||||
| type Kicker struct { | ||||
| 	Token      string | ||||
| 	Dispatcher *tb.Dispatcher | ||||
| 	Dispatcher *echotron.Dispatcher | ||||
| } | ||||
|  | ||||
| func (b *Kicker) NewBot(chatID int64) tb.Bot { | ||||
| 	d := db.GetDatabase() | ||||
| func (b *Kicker) NewBot(chatID int64) echotron.Bot { | ||||
| 	store := tongo.NewStore[db.Chat](Client) | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||||
| 	defer cancel() | ||||
| 	chat := db.Chat{ | ||||
| 		Id:      chatID, | ||||
| 		Title:   "", | ||||
| 		TopicId: 0, | ||||
| 	} | ||||
| 	if !d.ChatExists(ctx, chat) { | ||||
| 		if err := d.NewChat(ctx, chat); err != nil { | ||||
|  | ||||
| 	chat, err := store.GetOne(ctx, tongo.E("chat_id", chatID)) | ||||
| 	if err != nil { | ||||
| 		chat = &db.Chat{ | ||||
| 			Item:    tongo.NewID(), | ||||
| 			ChatId:  chatID, | ||||
| 			Title:   "", | ||||
| 			TopicId: 0, | ||||
| 		} | ||||
| 		if _, err := store.InsertOne(ctx, chat); err != nil { | ||||
| 			return &bot{} | ||||
| 		} | ||||
| 	} | ||||
| 	chat, _ = d.GetChat(ctx, chatID) | ||||
| 	CaptchaTopic := chat.TopicId | ||||
| 	result := &bot{ | ||||
| 		chatID, | ||||
| 		CaptchaTopic, | ||||
| 		nil, | ||||
| 		tb.NewAPI(b.Token), | ||||
| 		echotron.NewAPI(b.Token), | ||||
| 	} | ||||
| 	log.Println("New bot created with CaptchaTopic", result.CaptchaTopic) | ||||
| 	me, err := result.GetMe() | ||||
| 	if err != nil { | ||||
| 		log.Println(err) | ||||
| @ -81,23 +96,31 @@ func (b *Kicker) NewBot(chatID int64) tb.Bot { | ||||
|  | ||||
| // Initialize bot with token | ||||
| func (b *Kicker) Init() error { | ||||
| 	dsp := tb.NewDispatcher(b.Token, b.NewBot) | ||||
| 	dsp := echotron.NewDispatcher(b.Token, b.NewBot) | ||||
| 	b.Dispatcher = dsp | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Kicker) Start() error { | ||||
| 	return b.Dispatcher.Poll() | ||||
| 	return b.Dispatcher.PollOptions(true, echotron.UpdateOptions{ | ||||
| 		Timeout: 120, | ||||
| 		AllowedUpdates: []echotron.UpdateType{ | ||||
| 			echotron.MessageUpdate, | ||||
| 			echotron.ChatMemberUpdate, | ||||
| 			echotron.MyChatMemberUpdate, | ||||
| 			echotron.CallbackQueryUpdate, | ||||
| 		}, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func EscapeText(parseMode tb.ParseMode, text string) string { | ||||
| func EscapeText(parseMode echotron.ParseMode, text string) string { | ||||
| 	var replacer *strings.Replacer | ||||
|  | ||||
| 	if parseMode == tb.HTML { | ||||
| 	if parseMode == echotron.HTML { | ||||
| 		replacer = strings.NewReplacer("<", "<", ">", ">", "&", "&") | ||||
| 	} else if parseMode == tb.Markdown { | ||||
| 	} else if parseMode == echotron.Markdown { | ||||
| 		replacer = strings.NewReplacer("_", "\\_", "*", "\\*", "`", "\\`", "[", "\\[") | ||||
| 	} else if parseMode == tb.MarkdownV2 { | ||||
| 	} else if parseMode == echotron.MarkdownV2 { | ||||
| 		replacer = strings.NewReplacer( | ||||
| 			"_", "\\_", "*", "\\*", "[", "\\[", "]", "\\]", "(", | ||||
| 			"\\(", ")", "\\)", "~", "\\~", "`", "\\`", ">", "\\>", | ||||
| @ -110,3 +133,34 @@ func EscapeText(parseMode tb.ParseMode, text string) string { | ||||
|  | ||||
| 	return replacer.Replace(text) | ||||
| } | ||||
|  | ||||
| func waitAndDelete(b *echotron.API, message *echotron.Message, t time.Duration) { | ||||
| 	time.Sleep(t) | ||||
| 	if _, err := b.DeleteMessage(message.Chat.ID, message.ID); err != nil { | ||||
| 		log.Printf("Can't delay-delete message: %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func MentionUser(user *echotron.User) string { | ||||
| 	return fmt.Sprintf("[%s](tg://user?id=%d)", EscapeText(echotron.MarkdownV2, user.FirstName), user.ID) | ||||
| } | ||||
|  | ||||
| var chars = []string{"_", "\\*", "\\[", "\\]", "\\(", "\\)", "~", "`", ">", "#", "\\+", "\\-", "=", "|", "{", "}", "\\.", "!"} | ||||
| var r = strings.Join(chars, "") | ||||
| var reg = regexp.MustCompile("[" + r + "]+") | ||||
|  | ||||
| func EscapeMd2(s string) string { | ||||
| 	return reg.ReplaceAllString(s, "\\$0") | ||||
| } | ||||
|  | ||||
| func Mention(name string, id int64) string { | ||||
| 	return fmt.Sprintf("[%s](tg://user?id=%d)", EscapeMd2(name), id) | ||||
| } | ||||
|  | ||||
| func UserMention(u *echotron.User) string { | ||||
| 	return Mention(u.FirstName, u.ID) | ||||
| } | ||||
|  | ||||
| func UserMentionDB(u *db.User) string { | ||||
| 	return Mention(u.FirstName, u.UserId) | ||||
| } | ||||
|  | ||||
| @ -2,44 +2,65 @@ package kicker | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"kickerbot/db" | ||||
| 	"log" | ||||
| 	"time" | ||||
|  | ||||
| 	tb "github.com/NicoNex/echotron/v3" | ||||
| 	"go.mongodb.org/mongo-driver/bson" | ||||
| 	"go.mongodb.org/mongo-driver/bson/primitive" | ||||
| 	"git.nefrace.ru/nefrace/tongo" | ||||
| 	"github.com/NicoNex/echotron/v3" | ||||
| ) | ||||
|  | ||||
| type TaskBot struct { | ||||
| 	Token string | ||||
| 	tb.API | ||||
| 	echotron.API | ||||
| } | ||||
|  | ||||
| func TaskKickOldUsers(b *tb.API) { | ||||
| 	d := db.GetDatabase() | ||||
| //	log.Print("STARTING KICKING TASK") | ||||
| func TaskKickOldUsers(b *echotron.API) { | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) | ||||
| 	defer cancel() | ||||
| 	now := time.Now().Unix() | ||||
| 	old := now - 120 | ||||
| 	filter := bson.D{ | ||||
| 		primitive.E{Key: "date_joined", Value: bson.D{bson.E{Key: "$lt", Value: old}}}, | ||||
| 	} | ||||
| 	users, err := d.GetUsers(ctx, filter) | ||||
| 	now := time.Now() | ||||
| 	old := now.Add(-10 * time.Minute) | ||||
| 	store := tongo.NewStore[db.User](Client) | ||||
| 	users, err := store.GetMany(ctx, tongo.E("date_joined", tongo.D(tongo.E("$lt", old))), tongo.E("is_joined", false)) | ||||
| 	if err != nil { | ||||
| 		log.Printf("Error in deleting task: %v", err) | ||||
| 	} | ||||
| 	for _, user := range users { | ||||
|  | ||||
| 		_, err := b.BanChatMember(user.ChatId, user.Id, &tb.BanOptions{RevokeMessages: true}) | ||||
| 		_, err := b.BanChatMember(user.ChatId, user.UserId, &echotron.BanOptions{RevokeMessages: true}) | ||||
| 		if err != nil { | ||||
| 			log.Println("User was not banned: ", err) | ||||
| 			continue | ||||
| 		} | ||||
| 		log.Printf("User %s was banned", user.Id) | ||||
| 		b.DeleteMessage(user.ChatId, user.CaptchaMessage) | ||||
| 		b.DeleteMessage(user.ChatId, user.JoinedMessage) | ||||
| 		d.RemoveUser(ctx, user) | ||||
| 		log.Printf("User %s was banned", user.FirstName) | ||||
| 		store.DeleteByID(ctx, user.Id) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TaskNotifyUsers(b *echotron.API) { | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) | ||||
| 	defer cancel() | ||||
| 	store := tongo.NewStore[db.User](Client) | ||||
| 	chatStore := tongo.NewStore[db.Chat](Client) | ||||
| 	users, _ := store.GetMany(ctx, tongo.E("is_joined", false)) | ||||
| 	for _, user := range users { | ||||
| 		if time.Since(user.LastNotification) > 2*time.Minute { | ||||
| 			user.LastNotification = time.Now() | ||||
| 			text := fmt.Sprintf("*%s*, напоминаю, что тебе необходимо пройти капчу\\!", UserMentionDB(user)) | ||||
| 			store.ReplaceItem(ctx, *user, false) | ||||
| 			chat, err := chatStore.GetOne(ctx, tongo.E("chat_id", user.ChatId)) | ||||
| 			var topic int64 = 0 | ||||
| 			if err != nil { | ||||
| 				log.Printf("Can't get chat from user: %s", err) | ||||
| 				return | ||||
| 			} else { | ||||
| 				topic = chat.TopicId | ||||
| 			} | ||||
| 			res, err := b.SendMessage(text, user.ChatId, &echotron.MessageOptions{MessageThreadID: topic, ParseMode: echotron.MarkdownV2, ReplyToMessageID: user.CaptchaMessage}) | ||||
| 			if err != nil { | ||||
| 				log.Printf("Can't send notification to user: %s", err) | ||||
| 			} | ||||
| 			go waitAndDelete(b, res.Result, 2*time.Minute) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
							
								
								
									
										11
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								main.go
									
									
									
									
									
								
							| @ -2,17 +2,19 @@ package main | ||||
|  | ||||
| import ( | ||||
| 	"kickerbot/captchagen" | ||||
| 	"kickerbot/db" | ||||
| 	"kickerbot/kicker" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"time" | ||||
|  | ||||
| 	"git.nefrace.ru/nefrace/tongo" | ||||
| 	"github.com/NicoNex/echotron/v3" | ||||
| 	"github.com/go-co-op/gocron" | ||||
| 	"github.com/joho/godotenv" | ||||
| ) | ||||
|  | ||||
| var client *tongo.Database | ||||
|  | ||||
| func main() { | ||||
| 	err := godotenv.Load() | ||||
| 	captchagen.Init() | ||||
| @ -23,16 +25,19 @@ func main() { | ||||
| 	if !exists { | ||||
| 		log.Fatal("no token specified") | ||||
| 	} | ||||
| 	_, dberr := db.Init(os.Getenv("MONGO_URI")) | ||||
| 	if dberr != nil { | ||||
| 	client, err = tongo.NewConnection(os.Getenv("MONGO_URI"), "godotkicker") | ||||
| 	// _, dberr := db.Init(os.Getenv("MONGO_URI")) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	kicker.Client = client | ||||
|  | ||||
| 	Bot := kicker.Kicker{Token: token} | ||||
| 	Bot.Init() | ||||
| 	scheduler := gocron.NewScheduler(time.UTC) | ||||
| 	tasker := echotron.NewAPI(token) | ||||
| 	scheduler.Every(30).Seconds().Do(func() { kicker.TaskKickOldUsers(&tasker) }) | ||||
| 	scheduler.Every(30).Seconds().Do(func() { kicker.TaskNotifyUsers(&tasker) }) | ||||
| 	scheduler.StartAsync() | ||||
| 	Bot.Start() | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user