Fixes and refactor

This commit is contained in:
Nefrace 2023-06-13 02:22:44 +03:00
parent e1be5d24c4
commit 928149cb8e
8 changed files with 240 additions and 211 deletions

View File

@ -1,47 +1,14 @@
package main package main
import ( import (
"fmt"
neco "git.nefrace.ru/nefrace/nechotron" neco "git.nefrace.ru/nefrace/nechotron"
) )
var commandMe = neco.NewCommand("me", "Пишу ваш текст о вас в третьем лице", false) 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 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) 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) var commandWarn = neco.NewCommand("warn", "Делаю предупреждение пользователю", true)
func handleWarn(u *neco.Update) error { var defaultCommands = []*neco.Command{commandHelp, commandMe}
param := commandWarn.Param(u.Text()) var adminCommands = []*neco.Command{commandSay, commandWarn}
_, err := u.AnswerMarkdown(fmt.Sprintf("*_%s_*", neco.EscapeMd2(param))) var allCommands = append(defaultCommands, adminCommands...)
return err
}

View File

@ -44,3 +44,13 @@ func docRequest(u *neco.Update) bool {
u.Ctx = context.WithValue(u.Ctx, neco.FilteredValue("docTopic"), result["topic"]) u.Ctx = context.WithValue(u.Ctx, neco.FilteredValue("docTopic"), result["topic"])
return true return true
} }
func isFile(u *neco.Update) bool {
if u.Message == nil {
return false
}
if u.Message.Document == nil {
return false
}
return true
}

105
handle-docs.go Normal file
View File

@ -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
}

89
handle-karma.go Normal file
View File

@ -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
}

View File

@ -1,181 +1,37 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"log" "log"
"math/rand" "math/rand"
"net/http"
"net/url"
"strings"
"time"
"git.nefrace.ru/nefrace/nechotron" "git.nefrace.ru/nefrace/nechotron"
"git.nefrace.ru/nefrace/tongo" "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" // Docs
var docURL = "https://docs.godotengine.org/ru/stable/search.html?q=%s"
type DocResponse struct { func handleMe(u *nechotron.Update, text string) error {
Count uint `json:"count"` u.DeleteMessage()
Next string `json:"next"` _, err := u.AnswerMarkdown(fmt.Sprintf("_*%s* %s_", nechotron.EscapeMd2(u.From().FirstName), nechotron.EscapeMd2(text)))
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 return err
} }
func handleDocRequest3(u *nechotron.Update) error { var helpText = `
topic := strings.TrimPrefix(u.Callback(), "docs3:") Вот мои команды:
kb := nechotron.NewInlineKeyboard(). %s
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") Время сборки бота: %s`
if docerr != nil {
log.Println("Can't get docs: ", docerr) func handleHelp(u *nechotron.Update, text string) error {
} commands := nechotron.MakeCommandList("`%s` \\- _%s_\n", commandHelp, commandMe)
_, err := u.EditText(text, opts) _, err := u.AnswerMarkdown(fmt.Sprintf(helpText, commands, BuildTime))
return err return err
} }
func handleKarma(u *nechotron.Update) error { func handleSay(u *nechotron.Update, text string) error {
from, _ := u.Ctx.Value("userfrom").(*User) u.DeleteMessage()
to, _ := u.Ctx.Value("userto").(*User) _, err := u.AnswerMarkdown(fmt.Sprintf("*_%s_*", nechotron.EscapeMd2(text)))
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 return err
} }
@ -207,3 +63,10 @@ func handleDeleteCallback(u *nechotron.Update) error {
u.DeleteMessage() u.DeleteMessage()
return nil 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
}

View File

@ -1,9 +0,0 @@
package main
// Returns slices of good and bad triggers
func GetTriggers() map[string]int {
return map[string]int{
"+": 1,
"-": -1,
}
}

View File

@ -32,9 +32,6 @@ func main() {
Use(ErrorLogger). Use(ErrorLogger).
Use(ExecTimeLogger) Use(ExecTimeLogger)
api := echotron.NewAPI(token) 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.Any}, defaultCommands...)
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())

View File

@ -6,22 +6,29 @@ import (
var MainState = neco.State{ var MainState = neco.State{
Fn: func(u *neco.Update) error { Fn: func(u *neco.Update) error {
adminOnly := neco.NewDispatcher(). adminDispatcher := neco.NewDispatcher().
HandleCallback(neco.CallbackExact("delete"), handleDeleteCallback). 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(). mainCommands := neco.NewDispatcher().
HandleCommand(commandMe, handleMe). HandleCommand(commandMe, handleMe).
HandleCommand(commandHelp, handleHelp) HandleCommand(commandHelp, handleHelp)
replyDispatcher := neco.NewDispatcher(). replyDispatcher := neco.NewDispatcher().
HandleCommand(commandWarn, handleWarn).
HandleFilter(karmaTriggers, handleKarma) HandleFilter(karmaTriggers, handleKarma)
replies := neco.NewDispatcher(). replies := neco.NewDispatcher().
HandleFilter(neco.IsReply, replyDispatcher.Run) HandleFilter(neco.IsReply, replyDispatcher.Run)
docs := neco.NewDispatcher(). docs := neco.NewDispatcher().
HandleFilter(docRequest, handleDocRequest). HandleFilter(docRequest, handleDocRequest).
HandleCallback(neco.CallbackPrefix("docs3"), handleDocRequest3) HandleCallback(neco.CallbackPrefix("docs3"), handleDocRequest3)
triggers := neco.NewDispatcher(). triggers := neco.NewDispatcher().
HandleFilter(offtopTrigger, handleOfftop) HandleFilter(offtopTrigger, handleOfftop)
return neco.ChainRun(u, mainCommands, replies, docs, adminOnly, triggers)
return neco.RunEach(u, mainCommands, replies, docs, adminOnly, triggers)
}, },
} }