This commit is contained in:
nefrace 2025-06-02 18:17:32 +03:00
commit 0832ebf702
11 changed files with 865 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.db
go-dette
godette
godot.users.json

77
cmd/getdb/getdb.go Normal file
View File

@ -0,0 +1,77 @@
package main
import (
"encoding/json"
"log"
"os"
"time"
_ "github.com/glebarez/go-sqlite"
"github.com/jmoiron/sqlx"
)
var db *sqlx.DB
func InitDb() error {
newdb, err := sqlx.Connect("sqlite", "./bot.db?_time_format=sqlite")
if err != nil {
return err
}
db = newdb
return nil
}
func main() {
if err := InitDb(); err != nil {
log.Fatalln(err)
}
type User struct {
Id int64 `json:"uid" db:"id"`
Name string `json:"full_name" db:"name"`
Username string `json:"username" db:"username"`
MessageCount int `json:"messagesCount" db:"message_count"`
Karma int `json:"karma" db:"karma_history"`
KarmaSent int `json:"karmaChanged" db:"karma_sent_history"`
KarmaReceived int `json:"karmaGot" db:"karma_received_history"`
Created time.Time `db:"created"`
}
var users []User
data, _ := os.ReadFile("godot.users.json")
err := json.Unmarshal(data, &users)
if err != nil {
log.Fatal(err)
}
for _, user := range users {
var dbuser User
err := db.Get(&dbuser, `SELECT * FROM users WHERE id = $1`, user.Id)
if err != nil {
db.Exec(
`INSERT INTO users (id, name, username, message_count, karma_history, karma_sent_history, karma_received_history) VALUES ($1, $2, $3, $4, $5, $6, $7)`,
user.Id,
user.Name,
user.Username,
user.MessageCount,
user.Karma,
user.KarmaSent,
user.KarmaReceived,
)
db.Exec(
`INSERT INTO karma (from_user, to_user, change, message) VALUES (-1, $1, $2, "historical")`,
user.Id,
user.Karma,
)
} else {
if user.MessageCount > dbuser.MessageCount || user.Karma > dbuser.Karma {
_, err := db.Exec(`UPDATE users SET karma_history=$2, message_count=$3, karma_sent_history=$4, karma_received_history=$5 WHERE id=$1;`, user.Id, user.Karma, user.MessageCount, user.KarmaSent, user.KarmaReceived)
if err != nil {
log.Println(user.Id, err)
}
db.Exec(`UPDATE karma SET change=$2 WHERE from_user=-1 AND to_user=$1;`, user.Id, user.Karma)
}
}
}
}

29
dbtypes.go Normal file
View File

@ -0,0 +1,29 @@
package main
import "time"
type User struct {
Id int64 `db:"id"`
Name string `db:"name"`
Username string `db:"username"`
MessageCount int `db:"message_count"`
Karma int `db:"karma_history"`
KarmaSent int `db:"karma_sent_history"`
KarmaReceived int `db:"karma_received_history"`
Created time.Time `db:"created"`
}
type Karma struct {
Id int `db:"id"`
From int `db:"from_user"`
To int `db:"to_user"`
Change int `db:"change"`
Message string `db:"message"`
Created time.Time `db:"created"`
}
type TotalKarma struct {
Id int64 `db:"id"`
Name string `db:"name"`
Total int `db:"total"`
}

122
docs.go Normal file
View File

@ -0,0 +1,122 @@
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"strings"
"time"
"github.com/go-telegram/bot"
)
var docApiURL = "https://docs.godotengine.org/_/api/v3/search/?q=project:godot %s"
var docURL = "https://docs.godotengine.org/en/stable/search.html?q=%s"
var docApiURL_ru = "https://docs.godotengine.org/_/api/v3/search/?q=project:godot-ru %s"
var docURL_ru = "https://docs.godotengine.org/ru/4.x/search.html?q=%s"
var lastDocSearch = time.Now().Add(-1 * time.Hour)
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 getAndDecode[T any](u string) (*T, error) {
req, err := url.ParseRequestURI(u)
if err != nil {
log.Println("Can't parse url: ", err)
return nil, err
}
result, err := http.Get(req.String())
if err != nil {
log.Println("Can't get http: ", err)
return nil, err
}
defer result.Body.Close()
var response T
err = json.NewDecoder(result.Body).Decode(&response)
if err != nil {
return nil, err
}
return &response, nil
}
func getDocs(topic string, russian bool) (string, error) {
apiURL := docApiURL
pageURL := docURL
if russian {
apiURL = docApiURL_ru
pageURL = docURL_ru
}
since := time.Since(lastDocSearch)
GO_SEARCH_YOURSELF := fmt.Sprintf("\n\n[Попробуйте поискать самостоятельно\\!](%s)", fmt.Sprintf(pageURL, url.QueryEscape(topic)))
if since < 5*time.Second {
return "Извините, запросы происходят слишком часто" + GO_SEARCH_YOURSELF, nil
}
lastDocSearch = time.Now()
topic_escaped := bot.EscapeMarkdown(topic)
not_found := fmt.Sprintf("Извините, по запросу *%s* ничего не найдено\\."+GO_SEARCH_YOURSELF, topic_escaped)
exactUrl := fmt.Sprintf(apiURL, url.QueryEscape(topic))
looselyUrl := fmt.Sprintf(apiURL, url.QueryEscape(topic+"*"))
response, err := getAndDecode[DocResponse](exactUrl)
if err != nil || len(response.Results) == 0 {
response, err = getAndDecode[DocResponse](looselyUrl)
if err != nil || len(response.Results) == 0 {
return not_found, nil
}
}
textResults := ""
for i, r := range response.Results {
if i > 9 {
break
}
text := bot.EscapeMarkdown(r.Title)
link, _ := url.JoinPath(r.Domain, r.Path)
textResults += fmt.Sprintf("%d\\. [%s](%s)\n", i+1, text, link)
}
textResults += fmt.Sprintf("\n\n Или вы можете попробовать [поискать самостоятельно](%s)\\!", fmt.Sprintf(pageURL, topic))
text := fmt.Sprintf("Вот что я нашла по запросу *%s*: \n\n%s", topic_escaped, textResults)
return text, nil
}
func HandleDocRequest(g Godette) {
topic := strings.TrimPrefix(g.update.Message.Text, "/docs ")
text, docerr := getDocs(topic, false)
if docerr != nil {
log.Println("Can't get docs: ", docerr)
}
_, err := g.ReplyWithMarkdown(text)
if err != nil {
log.Println(err)
}
}
func HandleDocRequestRu(g Godette) {
topic := strings.TrimPrefix(g.update.Message.Text, "/docs_ru ")
text, docerr := getDocs(topic, true)
if docerr != nil {
log.Println("Can't get docs: ", docerr)
}
_, err := g.ReplyWithMarkdown(text)
if err != nil {
log.Println(err)
}
}

22
go.mod Normal file
View File

@ -0,0 +1,22 @@
module git.nefrace.ru/nefrace/go-dette
go 1.23.5
require (
github.com/glebarez/go-sqlite v1.22.0
github.com/go-telegram/bot v1.13.3
github.com/jmoiron/sqlx v1.4.0
)
require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.24 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
golang.org/x/sys v0.15.0 // indirect
modernc.org/libc v1.37.6 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.7.2 // indirect
modernc.org/sqlite v1.28.0 // indirect
)

36
go.sum Normal file
View File

@ -0,0 +1,36 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-telegram/bot v1.13.3 h1:r2erpHI5rMQsR5TFWJ/XVqWHq9R228fcaejLFvXJsmM=
github.com/go-telegram/bot v1.13.3/go.mod h1:i2TRs7fXWIeaceF3z7KzsMt/he0TwkVC680mvdTFYeM=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw=
modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ=
modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=

244
karma.go Normal file
View File

@ -0,0 +1,244 @@
package main
import (
"context"
"database/sql"
"errors"
"fmt"
"log"
"strconv"
"github.com/go-telegram/bot"
"github.com/go-telegram/bot/models"
)
func KarmaChange(g Godette, change int) {
log.Println("karma...")
from := g.update.Message.From
if g.update.Message.ReplyToMessage == nil {
return
}
to := g.update.Message.ReplyToMessage.From
if g.update.Message.ReplyToMessage.ForumTopicCreated != nil {
return
}
// Sent karma to themself
if from.ID == to.ID {
text, err := GetRandomTemplateByTag("karma_self")
if err != nil {
text = "_Осуждаю самолайки_"
}
// b.SendMessage(ctx, &sendMessageParams)
g.ReplyWithMarkdown(text)
return
}
// Sent karma to me
if me, err := g.GetMe(g.ctx); err == nil {
if to.ID == me.ID {
text, err := GetRandomTemplateByTag("karma_me")
if err != nil {
text = "_Спасибо, но мне это не нужно_"
}
g.ReplyWithMarkdown(text)
return
}
}
k := Karma{}
if err := db.Get(&k, `SELECT * FROM karma WHERE from_user=$1 AND to_user=$2 AND strftime("%s", created) > strftime("%s", datetime("now"), "-1 minutes");`, from.ID, to.ID, change); err != nil {
if errors.Is(err, sql.ErrNoRows) {
log.Println("karma not found")
_, insert_err := db.Exec(`INSERT INTO KARMA (from_user, to_user, change, message) VALUES ($1, $2, $3, $4)`, from.ID, to.ID, change, g.update.Message.Text)
log.Println("Insert karma error:", insert_err)
var from_karma, to_karma int
db.Get(&from_karma, `SELECT total FROM total_karma WHERE id=$1`, from.ID)
db.Get(&to_karma, `SELECT total FROM total_karma WHERE id=$1`, to.ID)
tag_text := "raise"
karma_text := "повысил"
if change < 0 {
tag_text = "lower"
karma_text = "понизил"
}
default_karma_text := fmt.Sprintf(
`*%[1]s \(%[3]d\)* %[5]s карму *%[2]s \(%[4]d\)*`,
bot.EscapeMarkdown(from.FirstName),
bot.EscapeMarkdown(to.FirstName),
from_karma,
to_karma,
karma_text)
text, err := GetRandomTemplateByTag(fmt.Sprintf("karma_%s", tag_text))
if err != nil {
text = default_karma_text
}
g.ReplyWithMarkdown(text)
return
}
log.Println(err)
} else {
text, err := GetRandomTemplateByTag("too_fast")
if err != nil {
text = "_Ты слишком шустрый, попробуй ещё раз позднее\\._"
}
g.ReplyWithMarkdown(text)
}
}
func KarmaGoUp(ctx context.Context, b *bot.Bot, update *models.Update) {
KarmaChange(Godette{b, ctx, update}, 1)
}
func KarmaGoDown(ctx context.Context, b *bot.Bot, update *models.Update) {
KarmaChange(Godette{b, ctx, update}, -1)
}
func GetTopUsers(g Godette, reverse bool) {
type User struct {
Id int64 `db:"id"`
Name string `db:"name"`
Total int `db:"total"`
}
query := `SELECT * FROM total_karma ORDER BY TOTAL %s LIMIT 10;`
descent := "DESC"
header := "*Вот наш ТОП\\-10 пользователей:*\n\n"
if reverse {
descent = ""
header = "*Вот наш _ОТРИЦАТЕЛЬНЫЙ_ ТОП\\-10:*\n\n"
}
query = fmt.Sprintf(query, descent)
users := []User{}
err := db.Select(&users, query)
if err != nil {
log.Println("can't top users:", err)
}
textResult := ""
for i, user := range users {
name := bot.EscapeMarkdown(user.Name)
if user.Id == g.update.Message.From.ID {
name = "_*" + name + "*_"
}
textResult += fmt.Sprintf("%d \\- %s \\(%s\\)\n", i, name, bot.EscapeMarkdown(strconv.Itoa(user.Total)))
}
_, send_err := g.Bot.SendMessage(g.ctx, &bot.SendMessageParams{
Text: fmt.Sprintf("%s%s", header, textResult),
ParseMode: models.ParseModeMarkdown,
ChatID: g.update.Message.Chat.ID,
MessageThreadID: g.update.Message.MessageThreadID,
})
if send_err != nil {
log.Println("can't send top: ", send_err)
}
}
func HandleUsersTop(g Godette) {
GetTopUsers(g, false)
}
func HandleUsersBottom(g Godette) {
GetTopUsers(g, true)
}
func HandleStats(g Godette) {
user := g.update.Message.From
userinfo := User{}
var total_karma, karma_sent, karma_received, place int
var same_karma []TotalKarma
uerr := db.Get(&userinfo, `SELECT * FROM users WHERE id=$1;`, user.ID)
if uerr != nil {
g.ReplyWithText("Не могу найти пользователя")
log.Println("can't find user info:", uerr)
}
db.Get(&total_karma, `SELECT total FROM total_karma WHERE id=$1;`, user.ID)
db.Get(&karma_sent, `SELECT COUNT(*) FROM karma WHERE from_user=$1;`, user.ID)
db.Get(&karma_received, `SELECT COUNT(*) FROM karma WHERE to_user=$1 AND from_user!=-1;`, user.ID)
db.Get(&place, `SELECT COUNT(DISTINCT(total)) FROM total_karma WHERE total > $1`, total_karma)
db.Select(&same_karma, `SELECT * FROM total_karma WHERE total = $1`, total_karma)
same_karma_text := ""
if len(same_karma) > 1 {
same_karma_text += "\nПользователи с такой же кармой: "
count := 0
for _, u := range same_karma {
if u.Id == user.ID {
continue
}
same_karma_text += bot.EscapeMarkdown(u.Name)
count += 1
if count == 5 {
same_karma_text += fmt.Sprintf(" \\(и ещё %d\\)", len(same_karma)-5)
break
}
same_karma_text += ", "
}
}
text := `
Вот что я знаю о тебе, *%[1]s*:
Примерное количество сообщений: *%[5]d*
Твоя карма: *%[2]s*
Кармы отправил: *%[6]d*
Кармы получил: *%[7]d*
Примерное место среди пользователей: *%[3]d* %[4]s
`
text_formatted := fmt.Sprintf(
text,
bot.EscapeMarkdown(user.FirstName),
bot.EscapeMarkdown(strconv.Itoa(total_karma)),
place+1, same_karma_text,
userinfo.MessageCount,
karma_sent+userinfo.KarmaSent,
karma_received+userinfo.KarmaReceived,
)
_, err := g.ReplyWithMarkdown(text_formatted)
if err != nil {
log.Println("can't send status:", err)
fmt.Println(text_formatted)
}
}
func HandleReactions(ctx context.Context, b *bot.Bot, u *models.Update) {
reaction := u.MessageReaction
had_like_before := false
for _, r := range reaction.OldReaction {
if r.Type == models.ReactionTypeTypeEmoji {
switch r.ReactionTypeEmoji.Emoji {
case "❤️", "👍":
had_like_before = true
}
}
}
has_like_now := false
for _, r := range reaction.NewReaction {
if r.Type == models.ReactionTypeTypeEmoji {
switch r.ReactionTypeEmoji.Emoji {
case "🩷", "👍":
has_like_now = true
}
}
}
if !had_like_before && has_like_now {
log.Println("Now have like")
} else if had_like_before && !has_like_now {
log.Println("Have no likes")
} else {
log.Println("likes didn't changed")
}
}

205
main.go Normal file
View File

@ -0,0 +1,205 @@
package main
import (
"context"
"fmt"
"log"
"os"
"os/signal"
"strings"
_ "github.com/glebarez/go-sqlite"
"github.com/go-telegram/bot"
"github.com/go-telegram/bot/models"
"github.com/jmoiron/sqlx"
)
var BUILD_TIME string
var db *sqlx.DB
type Godette struct {
*bot.Bot
ctx context.Context
update *models.Update
}
func MakeHandler(handler func(g Godette)) func(ctx context.Context, b *bot.Bot, update *models.Update) {
return func(ctx context.Context, b *bot.Bot, update *models.Update) {
if update.Message.Caption != "" && update.Message.Text == "" {
update.Message.Text = update.Message.Caption
}
handler(Godette{b, ctx, update})
}
}
func (g *Godette) ReplyWithText(text string) (*models.Message, error) {
return g.Bot.SendMessage(g.ctx, &bot.SendMessageParams{
Text: text,
ChatID: g.update.Message.Chat.ID,
MessageThreadID: g.update.Message.MessageThreadID,
ReplyParameters: &models.ReplyParameters{
ChatID: g.update.Message.Chat.ID,
MessageID: g.update.Message.ID,
},
})
}
func (g *Godette) AnswerWithMarkdown(text string) (*models.Message, error) {
return g.Bot.SendMessage(g.ctx, &bot.SendMessageParams{
Text: text,
ChatID: g.update.Message.Chat.ID,
MessageThreadID: g.update.Message.MessageThreadID,
ParseMode: models.ParseModeMarkdown,
})
}
func (g *Godette) ReplyWithMarkdown(text string) (*models.Message, error) {
return g.Bot.SendMessage(g.ctx, &bot.SendMessageParams{
Text: text,
ChatID: g.update.Message.Chat.ID,
MessageThreadID: g.update.Message.MessageThreadID,
ParseMode: models.ParseModeMarkdown,
ReplyParameters: &models.ReplyParameters{
ChatID: g.update.Message.Chat.ID,
MessageID: g.update.Message.ID,
},
})
}
func main() {
token := os.Getenv("TOKEN")
if token == "" {
panic("No token was provided")
}
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
if err := InitDb(); err != nil {
log.Fatalln(err)
}
opts := []bot.Option{
bot.WithDefaultHandler(defHandler),
bot.WithMiddlewares(writeUsersToDB),
bot.WithAllowedUpdates(bot.AllowedUpdates{
"message",
"callback_query",
"message_reaction",
}),
}
b, _ := bot.New(token, opts...)
b.RegisterHandler(bot.HandlerTypeMessageText, "/me ", bot.MatchTypePrefix, HandleMe)
b.RegisterHandler(bot.HandlerTypeMessageText, "/help", bot.MatchTypePrefix, MakeHandler(HandleHelp))
b.RegisterHandler(bot.HandlerTypeMessageText, "/docs ", bot.MatchTypePrefix, MakeHandler(HandleDocRequest))
b.RegisterHandler(bot.HandlerTypeMessageText, "/docs_ru ", bot.MatchTypePrefix, MakeHandler(HandleDocRequestRu))
b.RegisterHandler(bot.HandlerTypeMessageText, "/top", bot.MatchTypePrefix, MakeHandler(HandleUsersTop))
b.RegisterHandler(bot.HandlerTypeMessageText, "/bottom", bot.MatchTypePrefix, MakeHandler(HandleUsersBottom))
b.RegisterHandler(bot.HandlerTypeMessageText, "/stats", bot.MatchTypePrefix, MakeHandler(HandleStats))
b.RegisterHandler(bot.HandlerTypeMessageText, "+", bot.MatchTypePrefix, KarmaGoUp)
b.RegisterHandler(bot.HandlerTypeMessageText, "Спасибо", bot.MatchTypePrefix, KarmaGoUp)
b.RegisterHandler(bot.HandlerTypeMessageText, "спасибо", bot.MatchTypePrefix, KarmaGoUp)
b.RegisterHandler(bot.HandlerTypeMessageText, "СПАСИБО", bot.MatchTypePrefix, KarmaGoUp)
b.RegisterHandler(bot.HandlerTypeMessageText, "-", bot.MatchTypePrefix, KarmaGoDown)
b.RegisterHandlerMatchFunc(func(update *models.Update) bool {
return update.MessageReaction != nil
}, HandleReactions)
b.SetMyCommands(context.Background(), &bot.SetMyCommandsParams{
Commands: commands,
Scope: &models.BotCommandScopeDefault{},
})
b.Start(ctx)
}
func InitDb() error {
newdb, err := sqlx.Connect("sqlite", "./bot.db?_time_format=sqlite")
if err != nil {
return err
}
db = newdb
return nil
}
func defHandler(ctx context.Context, b *bot.Bot, update *models.Update) {
}
func HandleMe(ctx context.Context, b *bot.Bot, update *models.Update) {
g := Godette{b, ctx, update}
g.AnswerWithMarkdown(fmt.Sprintf(
"_*%s* %s_",
bot.EscapeMarkdown(update.Message.From.FirstName),
bot.EscapeMarkdown(strings.TrimPrefix(update.Message.Text, "/me ")),
))
b.DeleteMessage(ctx, &bot.DeleteMessageParams{
ChatID: update.Message.Chat.ID,
MessageID: update.Message.ID,
})
}
var commands = []models.BotCommand{
{Command: "/help", Description: "Показать данное сообщение"},
{Command: "/me", Description: "Написать своё сообщение от третьего лица"},
{Command: "/top", Description: "Вывод ТОП-10 пользователей"},
{Command: "/bottom", Description: "Отрицательный ТОП-10"},
{Command: "/stats", Description: "Информация о пользователе"},
{Command: "/docs", Description: "Поиск по документации"},
{Command: "/docs_ru", Description: "Поиск по русскоязычной документации"},
}
func HandleHelp(g Godette) {
commands_text := ""
for _, command := range commands {
commands_text += fmt.Sprintf("`%s` \\- %s\n", bot.EscapeMarkdown(command.Command), bot.EscapeMarkdown(command.Description))
}
log.Println(g.ReplyWithMarkdown(fmt.Sprintf(
`
Мои команды:
%s
Дата сборки бота: %s
`,
commands_text,
bot.EscapeMarkdown(BUILD_TIME),
)))
}
func GetRandomTemplateByTag(tag string) (string, error) {
var msg string
err := db.Get(
&msg,
`SELECT text FROM message_templates WHERE tag=$1 ORDER BY RANDOM() LIMIT 1;`,
tag,
)
return msg, err
}
func writeUsersToDB(next bot.HandlerFunc) bot.HandlerFunc {
return func(ctx context.Context, bot *bot.Bot, update *models.Update) {
if update.Message != nil {
user := update.Message.From
chat := update.Message.Chat
_, err := db.Exec(
`
INSERT INTO users(id, name, username) VALUES($1, $2, $3) ON CONFLICT(id) DO UPDATE SET name=$2, username=$3, message_count=message_count+1;
INSERT INTO chats(id, name, username) VALUES($4, $5, $6) ON CONFLICT(id) DO UPDATE SET name=$5, username=$6;
`,
user.ID,
strings.TrimSpace(fmt.Sprintf("%s %s", user.FirstName, user.LastName)),
user.Username,
chat.ID,
chat.FirstName,
chat.Username,
)
if err != nil {
log.Println(err)
}
}
next(ctx, bot, update)
}
}

View File

@ -0,0 +1,94 @@
-- +goose Up
-- +goose StatementBegin
SELECT 'up SQL query';
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
username TEXT DEFAULT "",
created DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS chats (
id INTEGER PRIMARY KEY,
name TEXT,
username TEXT DEFAULT "",
created DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS admins (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
chat_id INTEGER NOT NULL,
created DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users (id),
FOREIGN KEY (chat_id) REFERENCES chats (id)
);
CREATE TABLE IF NOT EXISTS karma (
id INTEGER PRIMARY KEY AUTOINCREMENT,
from_user INTEGER NOT NULL,
to_user INTEGER NOT NULL,
change INTEGER,
message TEXT DEFAULT "",
created DATETIME DEFAULT CURRENT_TIMESTAMP,
CHECK(from_user != to_user),
FOREIGN KEY (from_user) REFERENCES users(id),
FOREIGN KEY (to_user) REFERENCES users(id)
);
CREATE TABLE IF NOT EXISTS warnings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user INTEGER NOT NULL,
admin INTEGER NOT NULL,
message_id INTEGER DEFAULT 0,
topic_id INTEGER DEFAULT 0,
chat_id INTEGER NOT NULL,
active INTEGER DEFAULT 1,
reason TEXT DEFAULT "",
created DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user) REFERENCES users (id),
FOREIGN KEY (admin) REFERENCES users (id),
FOREIGN KEY (chat_id) REFERENCES chats (id)
);
CREATE TABLE IF NOT EXISTS admin_topics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
chat_id INTEGER NOT NULL,
topic_id INTEGER NOT NULL,
created DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (chat_id) REFERENCES chats (id)
);
CREATE TABLE IF NOT EXISTS message_templates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tag TEXT NOT NULL,
text TEXT NOT NULL,
triggers TEXT,
created DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
SELECT 'down SQL query';
DROP TABLE users ;
DROP TABLE chats ;
DROP TABLE admins ;
DROP TABLE karma ;
DROP TABLE warnings ;
DROP TABLE admin_topics ;
DROP TABLE message_templates ;
-- +goose StatementEnd

View File

@ -0,0 +1,15 @@
-- +goose Up
-- +goose StatementBegin
SELECT 'up SQL query';
CREATE VIEW IF NOT EXISTS total_karma AS SELECT u.id, u.name, sum(change) as total from karma
INNER JOIN users u ON u.id=karma.to_user
WHERE 1
GROUP BY u.id
ORDER BY total DESC;
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
SELECT 'down SQL query';
DROP VIEW total_karma
-- +goose StatementEnd

View File

@ -0,0 +1,17 @@
-- +goose Up
-- +goose StatementBegin
SELECT 'up SQL query';
ALTER TABLE users ADD COLUMN message_count INTEGER DEFAULT 0;
ALTER TABLE users ADD COLUMN karma_history INTEGER DEFAULT 0;
ALTER TABLE users ADD COLUMN karma_sent_history INTEGER DEFAULT 0;
ALTER TABLE users ADD COLUMN karma_received_history INTEGER DEFAULT 0;
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
SELECT 'down SQL query';
ALTER TABLE users DROP COLUMN message_count;
ALTER TABLE users DROP COLUMN karma_sent_history;
ALTER TABLE users DROP COLUMN karma_received_history;
-- +goose StatementEnd