init
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
*.db
 | 
			
		||||
go-dette
 | 
			
		||||
godette
 | 
			
		||||
godot.users.json
 | 
			
		||||
							
								
								
									
										77
									
								
								cmd/getdb/getdb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								cmd/getdb/getdb.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										29
									
								
								dbtypes.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										122
									
								
								docs.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										22
									
								
								go.mod
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										36
									
								
								go.sum
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										244
									
								
								karma.go
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										205
									
								
								main.go
									
									
									
									
									
										Normal 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)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										94
									
								
								migrations/20250126155704_init.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								migrations/20250126155704_init.sql
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										15
									
								
								migrations/20250302015710_top_view.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								migrations/20250302015710_top_view.sql
									
									
									
									
									
										Normal 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
 | 
			
		||||
@ -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
 | 
			
		||||
		Reference in New Issue
	
	Block a user