From 928149cb8eb528fdd23ae24c2371b5cbf83c8ab9 Mon Sep 17 00:00:00 2001 From: Nefrace Date: Tue, 13 Jun 2023 02:22:44 +0300 Subject: [PATCH] Fixes and refactor --- commands.go | 39 +---------- filters.go | 10 +++ handle-docs.go | 105 ++++++++++++++++++++++++++++ handle-karma.go | 89 ++++++++++++++++++++++++ handlers.go | 181 ++++++------------------------------------------ karma.go | 9 --- main.go | 3 - states.go | 15 ++-- 8 files changed, 240 insertions(+), 211 deletions(-) create mode 100644 handle-docs.go create mode 100644 handle-karma.go delete mode 100644 karma.go diff --git a/commands.go b/commands.go index 08fbffc..0e931a7 100644 --- a/commands.go +++ b/commands.go @@ -1,47 +1,14 @@ package main import ( - "fmt" - neco "git.nefrace.ru/nefrace/nechotron" ) var commandMe = neco.NewCommand("me", "Пишу ваш текст о вас в третьем лице", false) - -func handleMe(u *neco.Update) error { - u.DeleteMessage() - param := commandMe.Param(u.Text()) - _, err := u.AnswerMarkdown(fmt.Sprintf("_*%s* %s_", neco.EscapeMd2(u.From().FirstName), neco.EscapeMd2(param))) - return err -} - var commandHelp = neco.NewCommand("help", "Показываю данный текст", false) - -var helpText = ` -Вот мои команды: -%s - -Время сборки бота: %s` - -func handleHelp(u *neco.Update) error { - commands := neco.MakeCommandList("`%s` \\- _%s_\n", commandHelp, commandMe) - _, err := u.AnswerMarkdown(fmt.Sprintf(helpText, commands, BuildTime)) - return err -} - var commandSay = neco.NewCommand("say", "Пишу ваш текст от своего имени.", true) - -func handleSay(u *neco.Update) error { - u.DeleteMessage() - param := commandSay.Param(u.Text()) - _, err := u.AnswerMarkdown(fmt.Sprintf("*_%s_*", neco.EscapeMd2(param))) - return err -} - 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 -} +var defaultCommands = []*neco.Command{commandHelp, commandMe} +var adminCommands = []*neco.Command{commandSay, commandWarn} +var allCommands = append(defaultCommands, adminCommands...) diff --git a/filters.go b/filters.go index 34bb820..a0bc008 100644 --- a/filters.go +++ b/filters.go @@ -44,3 +44,13 @@ func docRequest(u *neco.Update) bool { u.Ctx = context.WithValue(u.Ctx, neco.FilteredValue("docTopic"), result["topic"]) return true } + +func isFile(u *neco.Update) bool { + if u.Message == nil { + return false + } + if u.Message.Document == nil { + return false + } + return true +} diff --git a/handle-docs.go b/handle-docs.go new file mode 100644 index 0000000..025e9b4 --- /dev/null +++ b/handle-docs.go @@ -0,0 +1,105 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "net/url" + "strings" + + "git.nefrace.ru/nefrace/nechotron" +) + +var docApiURL = "https://docs.godotengine.org/_/api/v2/search/?q=%s&project=godot&version=%s&language=en" +var docURL = "https://docs.godotengine.org/ru/stable/search.html?q=%s" + +type DocResponse struct { + Count uint `json:"count"` + Next string `json:"next"` + Previous string `json:"previous"` + Results []DocResult `json:"results"` +} + +type DocResult struct { + Title string `json:"title"` + Domain string `json:"domain"` + Path string `json:"path"` + Highlights DocHighlights `json:"highlights"` +} + +type DocHighlights struct { + Title []string `json:"title"` +} + +func getDocs(topic string, version string) (string, error) { + topic_escaped := nechotron.EscapeMd2(topic) + not_found := fmt.Sprintf("Извините, по запросу *%s* ничего не найдено.", topic_escaped) + req, err := url.ParseRequestURI(fmt.Sprintf(docApiURL, url.QueryEscape(topic), version)) + if err != nil { + return not_found, err + } + result, err := http.Get(req.String()) + if err != nil { + return not_found, err + } + defer result.Body.Close() + var response DocResponse + err = json.NewDecoder(result.Body).Decode(&response) + if err != nil { + return not_found, err + } + textResults := "" + for i, r := range response.Results { + if i > 9 { + break + } + text := nechotron.EscapeMd2(r.Title) + link, _ := url.JoinPath(r.Domain, r.Path) + textResults += fmt.Sprintf("%d\\. [%s](%s)\n", i+1, text, link) + } + text := fmt.Sprintf("Вот что я нашла по запросу *%s* \\(для версии `%s`\\): \n\n%s", topic_escaped, version, textResults) + return text, nil +} + +func handleDocRequest(u *nechotron.Update) error { + topic := u.Ctx.Value(nechotron.FilteredValue("docTopic")).(string) + kb := nechotron.NewInlineKeyboard(). + Row( + nechotron.InButtonCallback("Дай для 3.5", fmt.Sprintf("docs3:%s", topic)), + nechotron.InButtonCallback("А на русском можно?", "rudocs")). + Row(nechotron.InButtonURL("Поищу сам", fmt.Sprintf(docURL, url.QueryEscape(topic)))). + Row(nechotron.InButtonCallback("Спасибо, не надо", "delete")) + opts := nechotron.NewOptions(). + MarkdownV2(). + ReplyTo(u.MessageID()). + ReplyMarkup(kb.Markup()). + MessageOptions() + + text, docerr := getDocs(topic, "latest") + if docerr != nil { + log.Println("Can't get docs: ", docerr) + } + _, err := u.AnswerText(text, opts) + return err +} + +func handleDocRequest3(u *nechotron.Update) error { + topic := strings.TrimPrefix(u.Callback(), "docs3:") + kb := nechotron.NewInlineKeyboard(). + Row( + nechotron.InButtonCallback("А на русском можно?", "rudocs")). + Row(nechotron.InButtonURL("Поищу сам", fmt.Sprintf(docURL, url.QueryEscape(topic)))). + Row(nechotron.InButtonCallback("Спасибо, не надо", "delete")) + opts := nechotron.NewOptions(). + MarkdownV2(). + ReplyMarkup(kb.Markup()). + MessageTextOptions() + + text, docerr := getDocs(topic, "3.5") + if docerr != nil { + log.Println("Can't get docs: ", docerr) + } + _, err := u.EditText(text, opts) + return err +} diff --git a/handle-karma.go b/handle-karma.go new file mode 100644 index 0000000..0549b31 --- /dev/null +++ b/handle-karma.go @@ -0,0 +1,89 @@ +package main + +import ( + "fmt" + "time" + + "git.nefrace.ru/nefrace/nechotron" + "git.nefrace.ru/nefrace/tongo" + "github.com/NicoNex/echotron/v3" +) + +// Returns slices of good and bad triggers +func GetTriggers() map[string]int { + return map[string]int{ + "+": 1, + "-": -1, + } +} + +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) + if from.ID == to.ID { + res, err := u.AnswerMarkdown( + fmt.Sprintf("Лайкать себя \\- плохая затея, *%s*", mentionFrom)) + go func() { + time.Sleep(10 * time.Second) + u.Bot.DeleteMessage(u.ChatID(), res.Result.ID) + }() + return err + } + value := u.Ctx.Value(nechotron.FilteredValue("karmaValue")).(int) + // trigger := u.Ctx.Value(nechotron.FilteredValue("karmaTrigger")).(string) + store := tongo.NewStore[KarmaShot](db) + fromKarma, _ := store.Count(u.Ctx, tongo.E("to", from.ID)) + totalFromKarma := from.KarmaOffset + fromKarma + if totalFromKarma < 0 { + res, err := u.AnswerText( + fmt.Sprintf("У тебя слишком маленькая карма *\\(%d\\), чтобы менять её другим\\.", totalFromKarma), + &echotron.MessageOptions{ParseMode: echotron.MarkdownV2, ReplyToMessageID: u.MessageID()}) + go waitAndDelete(u, u.ChatID(), res.Result.ID) + 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 waitAndDelete(u, u.ChatID(), res.Result.ID) + return err + } + if to.ID == u.Bot.Me.ID { + if value > 0 { + u.AnswerMarkdown("*_Ой, это мне?_*") + } else { + res, err := u.AnswerMarkdown("*_Кажется, вы ошиблись адресатом :/_*") + go waitAndDelete(u, 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 +} diff --git a/handlers.go b/handlers.go index 90c8b94..f7c6291 100644 --- a/handlers.go +++ b/handlers.go @@ -1,181 +1,37 @@ package main import ( - "encoding/json" "fmt" "log" "math/rand" - "net/http" - "net/url" - "strings" - "time" "git.nefrace.ru/nefrace/nechotron" "git.nefrace.ru/nefrace/tongo" - "github.com/NicoNex/echotron/v3" ) -var docApiURL = "https://docs.godotengine.org/_/api/v2/search/?q=%s&project=godot&version=%s&language=en" -var docURL = "https://docs.godotengine.org/ru/stable/search.html?q=%s" +// Docs -type DocResponse struct { - Count uint `json:"count"` - Next string `json:"next"` - Previous string `json:"previous"` - Results []DocResult `json:"results"` -} - -type DocResult struct { - Title string `json:"title"` - Domain string `json:"domain"` - Path string `json:"path"` - Highlights DocHighlights `json:"highlights"` -} - -type DocHighlights struct { - Title []string `json:"title"` -} - -func getDocs(topic string, version string) (string, error) { - topic_escaped := nechotron.EscapeMd2(topic) - not_found := fmt.Sprintf("Извините, по запросу *%s* ничего не найдено.", topic_escaped) - req, err := url.ParseRequestURI(fmt.Sprintf(docApiURL, url.QueryEscape(topic), version)) - if err != nil { - return not_found, err - } - result, err := http.Get(req.String()) - if err != nil { - return not_found, err - } - defer result.Body.Close() - var response DocResponse - err = json.NewDecoder(result.Body).Decode(&response) - if err != nil { - return not_found, err - } - textResults := "" - for i, r := range response.Results { - if i > 9 { - break - } - text := nechotron.EscapeMd2(r.Title) - link, _ := url.JoinPath(r.Domain, r.Path) - textResults += fmt.Sprintf("%d\\. [%s](%s)\n", i+1, text, link) - } - text := fmt.Sprintf("Вот что я нашла по запросу *%s* \\(для версии `%s`\\): \n\n%s", topic_escaped, version, textResults) - return text, nil -} - -func handleDocRequest(u *nechotron.Update) error { - topic := u.Ctx.Value(nechotron.FilteredValue("docTopic")).(string) - kb := nechotron.NewInlineKeyboard(). - Row( - nechotron.InButtonCallback("Дай для 3.5", fmt.Sprintf("docs3:%s", topic)), - nechotron.InButtonCallback("А на русском можно?", "rudocs")). - Row(nechotron.InButtonURL("Поищу сам", fmt.Sprintf(docURL, url.QueryEscape(topic)))). - Row(nechotron.InButtonCallback("Спасибо, не надо", "delete")) - opts := nechotron.NewOptions(). - MarkdownV2(). - ReplyTo(u.MessageID()). - ReplyMarkup(kb.Markup()). - MessageOptions() - - text, docerr := getDocs(topic, "latest") - if docerr != nil { - log.Println("Can't get docs: ", docerr) - } - _, err := u.AnswerText(text, opts) +func handleMe(u *nechotron.Update, text string) error { + u.DeleteMessage() + _, err := u.AnswerMarkdown(fmt.Sprintf("_*%s* %s_", nechotron.EscapeMd2(u.From().FirstName), nechotron.EscapeMd2(text))) return err } -func handleDocRequest3(u *nechotron.Update) error { - topic := strings.TrimPrefix(u.Callback(), "docs3:") - kb := nechotron.NewInlineKeyboard(). - Row( - nechotron.InButtonCallback("А на русском можно?", "rudocs")). - Row(nechotron.InButtonURL("Поищу сам", fmt.Sprintf(docURL, url.QueryEscape(topic)))). - Row(nechotron.InButtonCallback("Спасибо, не надо", "delete")) - opts := nechotron.NewOptions(). - MarkdownV2(). - ReplyMarkup(kb.Markup()). - MessageTextOptions() +var helpText = ` +Вот мои команды: +%s - text, docerr := getDocs(topic, "3.5") - if docerr != nil { - log.Println("Can't get docs: ", docerr) - } - _, err := u.EditText(text, opts) +Время сборки бота: %s` + +func handleHelp(u *nechotron.Update, text string) error { + commands := nechotron.MakeCommandList("`%s` \\- _%s_\n", commandHelp, commandMe) + _, err := u.AnswerMarkdown(fmt.Sprintf(helpText, commands, BuildTime)) return err } -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) - if from.ID == to.ID { - res, err := u.AnswerMarkdown( - fmt.Sprintf("Лайкать себя \\- плохая затея, *%s*", mentionFrom)) - go func() { - time.Sleep(10 * time.Second) - u.Bot.DeleteMessage(u.ChatID(), res.Result.ID) - }() - return err - } - value := u.Ctx.Value(nechotron.FilteredValue("karmaValue")).(int) - // trigger := u.Ctx.Value(nechotron.FilteredValue("karmaTrigger")).(string) - store := tongo.NewStore[KarmaShot](db) - fromKarma, _ := store.Count(u.Ctx, tongo.E("to", from.ID)) - totalFromKarma := from.KarmaOffset + fromKarma - if totalFromKarma < 0 { - res, err := u.AnswerText( - fmt.Sprintf("У тебя слишком маленькая карма *\\(%d\\), чтобы менять её другим\\.", totalFromKarma), - &echotron.MessageOptions{ParseMode: echotron.MarkdownV2, ReplyToMessageID: u.MessageID()}) - go waitAndDelete(u, u.ChatID(), res.Result.ID) - 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 waitAndDelete(u, u.ChatID(), res.Result.ID) - return err - } - if to.ID == u.Bot.Me.ID { - if value > 0 { - u.AnswerMarkdown("*_Ой, это мне?_*") - } else { - res, err := u.AnswerMarkdown("*_Кажется, вы ошиблись адресатом :/_*") - go waitAndDelete(u, 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)) +func handleSay(u *nechotron.Update, text string) error { + u.DeleteMessage() + _, err := u.AnswerMarkdown(fmt.Sprintf("*_%s_*", nechotron.EscapeMd2(text))) return err } @@ -207,3 +63,10 @@ func handleDeleteCallback(u *nechotron.Update) error { u.DeleteMessage() return nil } + +func handleUsersImport(u *nechotron.Update) error { + f, _ := u.Bot.GetFile(u.Message.Document.FileID) + file, _ := u.Bot.DownloadFile(f.Result.FilePath) + log.Println(string(file)) + return nil +} diff --git a/karma.go b/karma.go deleted file mode 100644 index 6754c60..0000000 --- a/karma.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -// Returns slices of good and bad triggers -func GetTriggers() map[string]int { - return map[string]int{ - "+": 1, - "-": -1, - } -} diff --git a/main.go b/main.go index b6d3893..fd5b853 100644 --- a/main.go +++ b/main.go @@ -32,9 +32,6 @@ func main() { Use(ErrorLogger). Use(ExecTimeLogger) api := echotron.NewAPI(token) - defaultCommands := []*nechotron.Command{commandHelp, commandMe} - adminCommands := []*nechotron.Command{commandSay, commandWarn} - allCommands := append(defaultCommands, adminCommands...) nechotron.SetMyCommands(api, "", echotron.BotCommandScope{Type: echotron.Any}, defaultCommands...) nechotron.SetMyCommands(api, "", echotron.BotCommandScope{Type: echotron.BCSTAllChatAdministrators}, allCommands...) log.Fatal(neco.DispatchPoll()) diff --git a/states.go b/states.go index 1d13798..fd6ad4c 100644 --- a/states.go +++ b/states.go @@ -6,22 +6,29 @@ import ( var MainState = neco.State{ Fn: func(u *neco.Update) error { - adminOnly := neco.NewDispatcher(). + adminDispatcher := neco.NewDispatcher(). HandleCallback(neco.CallbackExact("delete"), handleDeleteCallback). - HandleCommand(commandSay, handleSay) + HandleCommand(commandSay, handleSay). + HandleFilter(isFile, handleUsersImport) + adminOnly := neco.NewDispatcher(). + HandleFilter(neco.IsUserAdmin, adminDispatcher.Run) + mainCommands := neco.NewDispatcher(). HandleCommand(commandMe, handleMe). HandleCommand(commandHelp, handleHelp) + replyDispatcher := neco.NewDispatcher(). - HandleCommand(commandWarn, handleWarn). HandleFilter(karmaTriggers, handleKarma) replies := neco.NewDispatcher(). HandleFilter(neco.IsReply, replyDispatcher.Run) + docs := neco.NewDispatcher(). HandleFilter(docRequest, handleDocRequest). HandleCallback(neco.CallbackPrefix("docs3"), handleDocRequest3) + triggers := neco.NewDispatcher(). HandleFilter(offtopTrigger, handleOfftop) - return neco.ChainRun(u, mainCommands, replies, docs, adminOnly, triggers) + + return neco.RunEach(u, mainCommands, replies, docs, adminOnly, triggers) }, }