210 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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"
 | ||
| 
 | ||
| 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
 | ||
| }
 | ||
| 
 | ||
| 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
 | ||
| }
 | ||
| 
 | ||
| func handleOfftop(u *nechotron.Update) error {
 | ||
| 	text := "Держите [ссылку на оффтоп](%s)\\!"
 | ||
| 	offtopLink := "https://t.me/Godot_Engine_Offtop"
 | ||
| 	offtopAnswers, err := tongo.NewStore[TriggerText](db).GetMany(u.Ctx, tongo.E("trigger", "offtop"))
 | ||
| 	if err == nil {
 | ||
| 		if len(offtopAnswers) > 0 {
 | ||
| 			text = offtopAnswers[rand.Intn(len(offtopAnswers)-1)].Text
 | ||
| 		}
 | ||
| 	}
 | ||
| 	offtopUrl, err := tongo.NewStore[Config](db).GetOne(u.Ctx, tongo.E("name", "offtop_url"))
 | ||
| 	if err == nil {
 | ||
| 		offtopLink = offtopUrl.Value.(string)
 | ||
| 	}
 | ||
| 	text = fmt.Sprintf(text, offtopLink)
 | ||
| 	kb := nechotron.NewInlineKeyboard().Row(nechotron.InButtonCallback("Спасибо, не надо", "delete")).Markup()
 | ||
| 	opts := nechotron.NewOptions().
 | ||
| 		MarkdownV2().
 | ||
| 		ReplyTo(u.MessageID()).
 | ||
| 		ReplyMarkup(kb).
 | ||
| 		MessageOptions()
 | ||
| 	u.AnswerText(text, opts)
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| func handleDeleteCallback(u *nechotron.Update) error {
 | ||
| 	u.DeleteMessage()
 | ||
| 	return nil
 | ||
| }
 |