KarmaShots, TimeLogger
This commit is contained in:
parent
601174f764
commit
2a29f0b89d
|
@ -9,6 +9,7 @@ import (
|
||||||
var commandMe = neco.NewCommand("me", "Пишу ваш текст о вас в третьем лице", false)
|
var commandMe = neco.NewCommand("me", "Пишу ваш текст о вас в третьем лице", false)
|
||||||
|
|
||||||
func handleMe(u *neco.Update) error {
|
func handleMe(u *neco.Update) error {
|
||||||
|
u.DeleteMessage()
|
||||||
param := commandMe.Param(u.Text())
|
param := commandMe.Param(u.Text())
|
||||||
_, err := u.AnswerMarkdown(fmt.Sprintf("_*%s* %s_", neco.EscapeMd2(u.From().FirstName), neco.EscapeMd2(param)))
|
_, err := u.AnswerMarkdown(fmt.Sprintf("_*%s* %s_", neco.EscapeMd2(u.From().FirstName), neco.EscapeMd2(param)))
|
||||||
return err
|
return err
|
||||||
|
@ -31,9 +32,16 @@ func handleHelp(u *neco.Update) error {
|
||||||
var commandSay = neco.NewCommand("say", "Пишу ваш текст от своего имени.", true)
|
var commandSay = neco.NewCommand("say", "Пишу ваш текст от своего имени.", true)
|
||||||
|
|
||||||
func handleSay(u *neco.Update) error {
|
func handleSay(u *neco.Update) error {
|
||||||
|
u.DeleteMessage()
|
||||||
param := commandSay.Param(u.Text())
|
param := commandSay.Param(u.Text())
|
||||||
_, err := u.AnswerMarkdown(fmt.Sprintf("*_%s_*", neco.EscapeMd2(param)))
|
_, err := u.AnswerMarkdown(fmt.Sprintf("*_%s_*", neco.EscapeMd2(param)))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var commandWarn = neco.NewCommand("warn", "Делаю предупреждение пользователю", true)
|
var commandWarn = neco.NewCommand("warn", "Делаю предупреждение пользователю", true)
|
||||||
|
|
||||||
|
func handleWarn(u *neco.Update) error {
|
||||||
|
param := commandWarn.Param(u.Text())
|
||||||
|
_, err := u.AnswerMarkdown(fmt.Sprintf("*_%s_*", neco.EscapeMd2(param)))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
neco "git.nefrace.ru/nefrace/nechotron"
|
||||||
|
)
|
||||||
|
|
||||||
|
func karmaTriggers(u *neco.Update) bool {
|
||||||
|
good, bad := GetTriggers()
|
||||||
|
all := append(good, bad...)
|
||||||
|
text := u.Text()
|
||||||
|
for _, t := range all {
|
||||||
|
if strings.HasPrefix(text, t) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
73
handlers.go
73
handlers.go
|
@ -1,8 +1,73 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "git.nefrace.ru/nefrace/nechotron"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.nefrace.ru/nefrace/nechotron"
|
||||||
|
"git.nefrace.ru/nefrace/tongo"
|
||||||
|
"github.com/NicoNex/echotron/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleKarma(u *nechotron.Update) error {
|
||||||
|
from, _ := u.Ctx.Value("userfrom").(*User)
|
||||||
|
to, _ := u.Ctx.Value("userto").(*User)
|
||||||
|
mentionFrom := nechotron.UserMention(u.Message.From)
|
||||||
|
mentionTo := nechotron.UserMention(u.Message.ReplyToMessage.From)
|
||||||
|
good, bad := GetTriggers()
|
||||||
|
value := 0
|
||||||
|
text := u.Text()
|
||||||
|
if StringHasPrefix(text, good...) {
|
||||||
|
value = 1
|
||||||
|
}
|
||||||
|
if StringHasPrefix(text, bad...) {
|
||||||
|
value = -1
|
||||||
|
}
|
||||||
|
store := tongo.NewStore[KarmaShot](db)
|
||||||
|
fromKarma, _ := store.Count(u.Ctx, tongo.E("to", from.ID))
|
||||||
|
totalFromKarma := from.KarmaOffset + fromKarma
|
||||||
|
if totalFromKarma < 0 {
|
||||||
|
_, err := u.AnswerText(
|
||||||
|
fmt.Sprintf("У тебя слишком маленькая карма *\\(%d\\), чтобы менять её другим\\.", totalFromKarma),
|
||||||
|
&echotron.MessageOptions{ParseMode: echotron.MarkdownV2, ReplyToMessageID: u.MessageID()})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
timeThreshold := time.Now().Add(1 * -time.Minute)
|
||||||
|
recentShots, err := store.Count(
|
||||||
|
u.Ctx,
|
||||||
|
tongo.E("from", from.ID),
|
||||||
|
tongo.E("to", to.ID),
|
||||||
|
tongo.E("when", tongo.D(tongo.E("$gte", timeThreshold))))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if recentShots > 0 {
|
||||||
|
u.DeleteMessage()
|
||||||
|
res, err := u.AnswerMarkdown(
|
||||||
|
fmt.Sprintf("*%s*, ты только недавно менял карму *%s*\\. Подожди минуту\\.", mentionFrom, mentionTo))
|
||||||
|
go func() {
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
u.Bot.DeleteMessage(u.ChatID(), res.Result.ID)
|
||||||
|
}()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newShot := KarmaShot{
|
||||||
|
Item: tongo.NewID(),
|
||||||
|
From: from.ID,
|
||||||
|
To: to.ID,
|
||||||
|
MessageText: nechotron.GetText(u.Message.ReplyToMessage),
|
||||||
|
When: time.Now(),
|
||||||
|
Count: value,
|
||||||
|
}
|
||||||
|
store.InsertOne(u.Ctx, &newShot)
|
||||||
|
newKarma, _ := store.Count(u.Ctx, tongo.E("to", to.ID))
|
||||||
|
totalToKarma := to.KarmaOffset + newKarma
|
||||||
|
changeText := "повысил"
|
||||||
|
if value < 0 {
|
||||||
|
changeText = "понизил"
|
||||||
|
}
|
||||||
|
_, err = u.AnswerMarkdown(
|
||||||
|
fmt.Sprintf("*%s \\(%d\\)* только что %s карму *%s \\(%d\\)*", mentionFrom, totalFromKarma, changeText, mentionTo, totalToKarma))
|
||||||
|
return err
|
||||||
|
|
||||||
func handleAdmin(u *nechotron.Update) error {
|
|
||||||
u.AnswerPlain("Вы админ!")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Returns slices of good and bad triggers
|
||||||
|
func GetTriggers() ([]string, []string) {
|
||||||
|
return []string{"+", "спасибо", "благодарю", "👍"}, []string{"-", "👎"}
|
||||||
|
}
|
16
main.go
16
main.go
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -8,21 +9,26 @@ import (
|
||||||
"git.nefrace.ru/nefrace/tongo"
|
"git.nefrace.ru/nefrace/tongo"
|
||||||
"github.com/NicoNex/echotron/v3"
|
"github.com/NicoNex/echotron/v3"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
var BuildTime string
|
var BuildTime string
|
||||||
|
var db *tongo.Database
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
godotenv.Load()
|
godotenv.Load()
|
||||||
db, err := tongo.NewConnection(os.Getenv("MONGO_URI"), "godette")
|
var err error
|
||||||
|
db, err = tongo.NewConnection(os.Getenv("MONGO_URI"), "godette")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Can't connect to database: %v", err)
|
log.Fatalf("Can't connect to database: %v", err)
|
||||||
}
|
}
|
||||||
|
createIndexes(db)
|
||||||
token := os.Getenv("TELEGRAM_TOKEN")
|
token := os.Getenv("TELEGRAM_TOKEN")
|
||||||
neco := nechotron.NewTron(token, &MainState)
|
neco := nechotron.NewTron(token, &MainState)
|
||||||
neco.
|
neco.
|
||||||
Use(UserDBUpdater(db)).
|
Use(UserDBUpdater(db)).
|
||||||
Use(ErrorLogger)
|
Use(ErrorLogger).
|
||||||
|
Use(ExecTimeLogger)
|
||||||
api := echotron.NewAPI(token)
|
api := echotron.NewAPI(token)
|
||||||
defaultCommands := []*nechotron.Command{commandHelp, commandMe}
|
defaultCommands := []*nechotron.Command{commandHelp, commandMe}
|
||||||
adminCommands := []*nechotron.Command{commandSay, commandWarn}
|
adminCommands := []*nechotron.Command{commandSay, commandWarn}
|
||||||
|
@ -31,3 +37,9 @@ func main() {
|
||||||
nechotron.SetMyCommands(api, "", echotron.BotCommandScope{Type: echotron.BCSTAllChatAdministrators}, allCommands...)
|
nechotron.SetMyCommands(api, "", echotron.BotCommandScope{Type: echotron.BCSTAllChatAdministrators}, allCommands...)
|
||||||
log.Fatal(neco.DispatchPoll())
|
log.Fatal(neco.DispatchPoll())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createIndexes(db *tongo.Database) error {
|
||||||
|
userStore := tongo.NewStore[User](db)
|
||||||
|
_, err := userStore.Coll.Indexes().CreateOne(context.Background(), userIndex, options.CreateIndexes())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,16 @@ import (
|
||||||
"git.nefrace.ru/nefrace/tongo"
|
"git.nefrace.ru/nefrace/tongo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ExecTimeLogger(next nechotron.UpdateHandler) nechotron.UpdateHandler {
|
||||||
|
return func(u *nechotron.Update) error {
|
||||||
|
start := time.Now()
|
||||||
|
err := next(u)
|
||||||
|
t := time.Since(start)
|
||||||
|
log.Println("Update was handled in %d microseconds", t.Microseconds())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func UserLogger(next nechotron.UpdateHandler) nechotron.UpdateHandler {
|
func UserLogger(next nechotron.UpdateHandler) nechotron.UpdateHandler {
|
||||||
return func(u *nechotron.Update) error {
|
return func(u *nechotron.Update) error {
|
||||||
log.Println(u.From().FirstName)
|
log.Println(u.From().FirstName)
|
||||||
|
@ -20,24 +30,21 @@ func UserLogger(next nechotron.UpdateHandler) nechotron.UpdateHandler {
|
||||||
func UserDBUpdater(db *tongo.Database) nechotron.Middleware {
|
func UserDBUpdater(db *tongo.Database) nechotron.Middleware {
|
||||||
return func(next nechotron.UpdateHandler) nechotron.UpdateHandler {
|
return func(next nechotron.UpdateHandler) nechotron.UpdateHandler {
|
||||||
return func(u *nechotron.Update) error {
|
return func(u *nechotron.Update) error {
|
||||||
store := tongo.NewStore[User](db)
|
|
||||||
from := u.From()
|
from := u.From()
|
||||||
user, err := store.GetOne(u.Ctx, tongo.E("id", from.ID))
|
userFrom, err := UpdateUser(u.Ctx, db, from, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
user = &User{
|
return err
|
||||||
Item: tongo.NewID(),
|
}
|
||||||
ID: from.ID,
|
u.Ctx = context.WithValue(u.Ctx, "userfrom", userFrom)
|
||||||
|
if u.IsMessage() && u.Message.ReplyToMessage != nil {
|
||||||
|
to := u.Message.ReplyToMessage.From
|
||||||
|
userTo, err := UpdateUser(u.Ctx, db, to, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
u.Ctx = context.WithValue(u.Ctx, "userto", userTo)
|
||||||
}
|
}
|
||||||
user.FirstName = from.FirstName
|
|
||||||
user.LastName = from.LastName
|
|
||||||
user.Username = from.Username
|
|
||||||
user.LastMessage = time.Now()
|
|
||||||
err = store.ReplaceItem(u.Ctx, *user, true)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Cant replace user: ", err)
|
|
||||||
}
|
|
||||||
u.Ctx = context.WithValue(u.Ctx, "dbuser", user)
|
|
||||||
return next(u)
|
return next(u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,16 @@ import (
|
||||||
|
|
||||||
var MainState = neco.State{
|
var MainState = neco.State{
|
||||||
Fn: func(u *neco.Update) error {
|
Fn: func(u *neco.Update) error {
|
||||||
disp := neco.NewDispatcher().
|
mainCommands := neco.NewDispatcher().
|
||||||
HandleCommand(commandMe, handleMe).
|
HandleCommand(commandMe, handleMe).
|
||||||
HandleCommand(commandHelp, handleHelp).
|
HandleCommand(commandHelp, handleHelp).
|
||||||
HandleCommand(commandSay, handleSay)
|
HandleCommand(commandSay, handleSay)
|
||||||
|
replyDispatcher := neco.NewDispatcher().
|
||||||
|
HandleCommand(commandWarn, handleWarn).
|
||||||
|
HandleFilter(karmaTriggers, handleKarma)
|
||||||
|
replies := neco.NewDispatcher().
|
||||||
|
HandleFilter(neco.IsReply, replyDispatcher.Run)
|
||||||
|
|
||||||
return disp.Run(u)
|
return neco.ChainRun(u, mainCommands, replies)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
55
types.go
55
types.go
|
@ -1,9 +1,12 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.nefrace.ru/nefrace/tongo"
|
"git.nefrace.ru/nefrace/tongo"
|
||||||
|
"github.com/NicoNex/echotron/v3"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ tongo.Collectable = &User{}
|
var _ tongo.Collectable = &User{}
|
||||||
|
@ -14,20 +17,60 @@ type User struct {
|
||||||
FirstName string
|
FirstName string
|
||||||
LastName string
|
LastName string
|
||||||
ID int64
|
ID int64
|
||||||
KarmaOffset int
|
KarmaOffset int64
|
||||||
LastMessage time.Time
|
LastMessage time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateUser(ctx context.Context, db *tongo.Database, user *echotron.User, updateLastMessage bool) (*User, error) {
|
||||||
|
store := tongo.NewStore[User](db)
|
||||||
|
u, err := store.GetOne(ctx, tongo.E("id", user.ID))
|
||||||
|
if err != nil {
|
||||||
|
u = &User{
|
||||||
|
Item: tongo.NewID(),
|
||||||
|
ID: user.ID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u.FirstName = user.FirstName
|
||||||
|
u.LastName = user.LastName
|
||||||
|
u.Username = user.Username
|
||||||
|
if updateLastMessage {
|
||||||
|
u.LastMessage = time.Now()
|
||||||
|
}
|
||||||
|
err = store.ReplaceItem(ctx, *u, true)
|
||||||
|
if err != nil {
|
||||||
|
// log.Println("Cant replace user: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var userIndex = mongo.IndexModel{
|
||||||
|
Keys: tongo.D(tongo.E("id", 1)),
|
||||||
|
}
|
||||||
|
|
||||||
func (User) Coll() string { return "users" }
|
func (User) Coll() string { return "users" }
|
||||||
|
|
||||||
var _ tongo.Collectable = &KarmaShot{}
|
var _ tongo.Collectable = &KarmaShot{}
|
||||||
|
|
||||||
type KarmaShot struct {
|
type KarmaShot struct {
|
||||||
tongo.Item
|
tongo.Item `bson:",inline"`
|
||||||
From tongo.OID
|
From int64
|
||||||
To tongo.OID
|
To int64
|
||||||
Count int
|
Count int
|
||||||
When time.Time
|
MessageText string
|
||||||
|
When time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (KarmaShot) Coll() string { return "karma" }
|
func (KarmaShot) Coll() string { return "karma" }
|
||||||
|
|
||||||
|
type Warn struct {
|
||||||
|
tongo.Item `bson:",inline"`
|
||||||
|
From int64
|
||||||
|
To int64
|
||||||
|
MessageText string
|
||||||
|
WarnText string
|
||||||
|
When time.Time
|
||||||
|
Active bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Warn) Coll() string { return "warns" }
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func StringHasAny(s string, subs ...string) bool {
|
||||||
|
for _, sub := range subs {
|
||||||
|
if strings.Contains(s, sub) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringHasPrefix(s string, subs ...string) bool {
|
||||||
|
for _, sub := range subs {
|
||||||
|
if strings.HasPrefix(s, sub) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func StringHasSuffix(s string, subs ...string) bool {
|
||||||
|
for _, sub := range subs {
|
||||||
|
if strings.HasSuffix(s, sub) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
Loading…
Reference in New Issue