🔀 Merge branch 'develop'

This commit is contained in:
Maxim Lebedev 2018-06-25 01:12:00 +05:00
commit 41fcfd5f51
No known key found for this signature in database
GPG Key ID: F8978F46FF0FFA4F
44 changed files with 563 additions and 561 deletions

47
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,47 @@
image: golang:alpine
cache:
paths:
- /go/src/github.com
- /go/src/gitlab.com
- /go/src/golang.org
- /go/src/google.golang.org
- /go/src/gopkg.in
stages:
- test
- build
before_script:
- apk add --no-cache git build-base bash
- mkdir -p /go/src/gitlab.com/$CI_PROJECT_NAMESPACE /go/src/_/builds
- cp -r $CI_PROJECT_DIR /go/src/gitlab.com/$CI_PROJECT_PATH
- ln -s /go/src/gitlab.com/$CI_PROJECT_NAMESPACE /go/src/_/builds/$CI_PROJECT_NAMESPACE
- make dep
unit_tests:
stage: test
script:
- make test
.race_detector:
stage: test
script:
- make race
code_coverage:
stage: test
script:
- make coverage
lint_code:
stage: test
script:
- go get github.com/go-critic/go-critic/cmd/gocritic
- go install github.com/go-critic/go-critic/cmd/gocritic
- make lint
build:
stage: build
script:
- make

View File

@ -1,8 +0,0 @@
language: go
go:
- tip
install:
- go get -tags=debug
- go get -u github.com/nicksnyder/go-i18n/goi18n

View File

@ -1,31 +1,32 @@
# Build package by default with all general tools and things PROJECT_NAMESPACE := $(CI_PROJECT_NAMESPACE)
all: PROJECT_NAME := $(CI_PROJECT_NAME)
make localization PROJECT_PATH := $(PROJECT_NAMESPACE)/$(PROJECT_NAME)
make build PACKAGE_NAME := "gitlab.com/$(PROJECT_PATH)"
PACKAGE_PATH := $(GOPATH)/src/$(PACKAGE_NAME)
PACKAGE_LIST := $(shell go list $(PACKAGE_NAME)/... | grep -v /vendor/)
GO_FILES := $(shell find . -name '*.go' | grep -v /vendor/ | grep -v _test.go)
# Build minimal package only .PHONY: all lint test rase coverage dep build clean
build:
go build
# Build debug version with more logs all: build
debug:
go build -tags=debug
# Format the source code lint: ## Lint the files
fmt: @gocritic check-project $(PACKAGE_PATH)
go fmt
# Build localization files with separated untranslated strings race: dep ## Run data race detector
translation: @go test -race -short ${PACKAGE_LIST}
goi18n merge -format yaml \
-sourceLanguage en \
-outdir ./i18n/ \
./i18n/src/*/*
# Build localization files and merge untranslated strings coverage: ## Generate global code coverage report
localization: @go test -cover -v -coverpkg=$(PACKAGE_NAME) ${PACKAGE_LIST}
make translation
goi18n -format yaml \ dep: ## Get the dependencies
-sourceLanguage en \ @go get -v -d -t ${PACKAGE_LIST}
-outdir ./i18n/ \
./i18n/*.all.yaml ./i18n/*.untranslated.yaml build: dep ## Build the binary file
@go build -i -v $(PACKAGE_NAME)
clean: ## Remove previous build
@rm -f $(PROJECT_NAME)
help: ## Display this help screen
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

View File

@ -1,20 +0,0 @@
<!--
Welcome to my repo! 👋
Need help or you have a question? Please come chat in Discord: https://discord.gg/KYQB9FR
Found a bug? Want a new feature? Please fill out the sections below. Thanks! 👍
-->
### Summary
<!-- A summary of the issue or, maybe, your ideas for the feature. -->
### How-To
<!--
1. This is the first step
2. This is the second step, etc.
Any other info e.g. Why do you consider this to be a bug? What did you expect to happen instead?
If this is a feature, then describe how it works, what it can potentially be useful, and so on.
P.S.: Bugs are always in priority over the new functionality, unless, of course, it was offered by a sponsor on my Patreon: https://patreon.com/toby3d
-->

View File

@ -1,16 +0,0 @@
<!--
Thanks for your help to my repo! 👋
Need help or you have a question? Please come chat in Discord: https://discord.gg/KYQB9FR
Fixed a bug? Added new feature? Make a new translation? Please fill out the section below. Thanks! 👍
-->
### Summary
<!--
Describe the essence of your commits.
- Is it a fix, feature or a translation?
- What issue is closed by your commits?
- You are totally sure what are you removed all warnings by [gometalinter](https://github.com/alecthomas/gometalinter)?
- Your code is compiled without errors?
- Your code works without obvious errors?
-->

View File

@ -1,28 +0,0 @@
package init
import (
log "github.com/kirillDanshin/dlog"
"github.com/toby3d/MyPackBot/internal/bot"
"github.com/toby3d/MyPackBot/internal/config"
"github.com/toby3d/MyPackBot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors"
"github.com/toby3d/MyPackBot/internal/i18n"
)
// init prepare configuration and other things for successful start
func init() {
log.Ln("Initializing...")
// Preload localization strings
err := i18n.Open("i18n/")
errors.Check(err)
// Preload configuration file
config.Open("configs/config.yaml")
// Open database or create new one
db.Open("stickers.db")
// Create bot with credentials from config
bot.New()
}

View File

@ -2,16 +2,16 @@ package actions
import ( import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/models"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Action function check Message update on commands, sended stickers or other // Action function check Message update on commands, sended stickers or other
// user stuff if user state is not 'none' // user stuff if user state is not 'none'
func Action(msg *tg.Message) { func Action(msg *tg.Message) {
state, err := db.UserState(msg.From.ID) state, err := db.DB.GetUserState(msg.From)
errors.Check(err) errors.Check(err)
log.Ln("state:", state) log.Ln("state:", state)
@ -27,7 +27,7 @@ func Action(msg *tg.Message) {
case models.StateReset: case models.StateReset:
Reset(msg) Reset(msg)
default: default:
err = db.ChangeUserState(msg.From.ID, models.StateNone) err = db.DB.ChangeUserState(msg.From, models.StateNone)
errors.Check(err) errors.Check(err)
Error(msg) Error(msg)

View File

@ -2,13 +2,13 @@ package actions
import ( import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/helpers" "gitlab.com/toby3d/mypackbot/internal/i18n"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/models"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/utils"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Add action add sticker or set to user's pack // Add action add sticker or set to user's pack
@ -17,34 +17,32 @@ func Add(msg *tg.Message, pack bool) {
return return
} }
T, err := i18n.SwitchTo(msg.From.LanguageCode) t, err := i18n.SwitchTo(msg.From.LanguageCode)
errors.Check(err) errors.Check(err)
_, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping) _, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping)
errors.Check(err) errors.Check(err)
reply := tg.NewMessage(msg.Chat.ID, T("success_add_sticker")) reply := tg.NewMessage(msg.Chat.ID, t("success_add_sticker"))
reply.ParseMode = tg.ModeMarkdown reply.ParseMode = tg.StyleMarkdown
if !pack { if !pack {
var exist bool var exist bool
sticker := msg.Sticker sticker := msg.Sticker
exist, err = db.AddSticker( exist, err = db.DB.AddSticker(msg.From, sticker)
msg.From.ID, sticker.SetName, sticker.FileID, sticker.Emoji,
)
errors.Check(err) errors.Check(err)
if exist { if exist {
reply.Text = T("error_already_add_sticker") reply.Text = t("error_already_add_sticker")
} }
reply.ReplyMarkup = helpers.CancelButton(T) reply.ReplyMarkup = utils.CancelButton(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)
return return
} }
reply.Text = T("error_empty_add_pack", map[string]interface{}{ reply.Text = t("error_empty_add_pack", map[string]interface{}{
"AddStickerCommand": models.CommandAddSticker, "AddStickerCommand": models.CommandAddSticker,
}) })
@ -54,16 +52,14 @@ func Add(msg *tg.Message, pack bool) {
errors.Check(err) errors.Check(err)
log.Ln("SetTitle:", set.Title) log.Ln("SetTitle:", set.Title)
reply.Text = T("success_add_pack", map[string]interface{}{ reply.Text = t("success_add_pack", map[string]interface{}{
"SetTitle": set.Title, "SetTitle": set.Title,
}) })
allExists := true allExists := true
for _, sticker := range set.Stickers { for i := range set.Stickers {
var exist bool var exist bool
exist, err = db.AddSticker( exist, err = db.DB.AddSticker(msg.From, &set.Stickers[i])
msg.From.ID, sticker.SetName, sticker.FileID, sticker.Emoji,
)
errors.Check(err) errors.Check(err)
if !exist { if !exist {
@ -73,13 +69,13 @@ func Add(msg *tg.Message, pack bool) {
log.Ln("All exists?", allExists) log.Ln("All exists?", allExists)
if allExists { if allExists {
reply.Text = T("error_already_add_pack", map[string]interface{}{ reply.Text = t("error_already_add_pack", map[string]interface{}{
"SetTitle": set.Title, "SetTitle": set.Title,
}) })
} }
} }
reply.ReplyMarkup = helpers.CancelButton(T) reply.ReplyMarkup = utils.CancelButton(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)
} }

View File

@ -2,12 +2,12 @@ package actions
import ( import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/helpers" "gitlab.com/toby3d/mypackbot/internal/i18n"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/utils"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Delete action remove sticker or set from user's pack // Delete action remove sticker or set from user's pack
@ -16,15 +16,15 @@ func Delete(msg *tg.Message, pack bool) {
return return
} }
T, err := i18n.SwitchTo(msg.From.LanguageCode) t, err := i18n.SwitchTo(msg.From.LanguageCode)
errors.Check(err) errors.Check(err)
_, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping) _, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping)
errors.Check(err) errors.Check(err)
reply := tg.NewMessage(msg.Chat.ID, T("success_del_sticker")) reply := tg.NewMessage(msg.Chat.ID, t("success_del_sticker"))
reply.ParseMode = tg.ModeMarkdown reply.ParseMode = tg.StyleMarkdown
reply.ReplyMarkup = helpers.CancelButton(T) reply.ReplyMarkup = utils.CancelButton(t)
var notExist bool var notExist bool
if pack { if pack {
@ -33,22 +33,18 @@ func Delete(msg *tg.Message, pack bool) {
errors.Check(err) errors.Check(err)
log.Ln("SetName:", set.Title) log.Ln("SetName:", set.Title)
reply.Text = T("success_del_pack", map[string]interface{}{ reply.Text = t("success_del_pack", map[string]interface{}{
"SetTitle": set.Title, "SetTitle": set.Title,
}) })
notExist, err = db.DeletePack(msg.From.ID, msg.Sticker.SetName) notExist, err = db.DB.DeletePack(msg.From, msg.Sticker)
if notExist { if notExist {
reply.Text = T("error_already_del_pack") reply.Text = t("error_already_del_pack")
} }
} else { } else {
notExist, err = db.DeleteSticker( notExist, err = db.DB.DeleteSticker(msg.From, msg.Sticker)
msg.From.ID,
msg.Sticker.SetName,
msg.Sticker.FileID,
)
if notExist { if notExist {
reply.Text = T("error_already_del_sticker") reply.Text = t("error_already_del_sticker")
} }
} }
errors.Check(err) errors.Check(err)

View File

@ -1,32 +1,32 @@
package actions package actions
import ( import (
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/helpers" "gitlab.com/toby3d/mypackbot/internal/i18n"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/models"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/utils"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Error action send error reply about invalid user request // Error action send error reply about invalid user request
func Error(msg *tg.Message) { func Error(msg *tg.Message) {
T, err := i18n.SwitchTo(msg.From.LanguageCode) t, err := i18n.SwitchTo(msg.From.LanguageCode)
errors.Check(err) errors.Check(err)
_, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping) _, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping)
errors.Check(err) errors.Check(err)
reply := tg.NewMessage( reply := tg.NewMessage(
msg.Chat.ID, T("error_unknown", map[string]interface{}{ msg.Chat.ID, t("error_unknown", map[string]interface{}{
"AddStickerCommand": models.CommandAddSticker, "AddStickerCommand": models.CommandAddSticker,
"AddPackCommand": models.CommandAddPack, "AddPackCommand": models.CommandAddPack,
"DeleteStickerCommand": models.CommandDeleteSticker, "DeleteStickerCommand": models.CommandDeleteSticker,
"DeletePackCommand": models.CommandDeletePack, "DeletePackCommand": models.CommandDeletePack,
}), }),
) )
reply.ParseMode = tg.ModeMarkdown reply.ParseMode = tg.StyleMarkdown
reply.ReplyMarkup = helpers.MenuKeyboard(T) reply.ReplyMarkup = utils.MenuKeyboard(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)

View File

@ -3,42 +3,42 @@ package actions
import ( import (
"strings" "strings"
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/helpers" "gitlab.com/toby3d/mypackbot/internal/i18n"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/models"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/utils"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Reset action checks key phrase and reset user's pack // Reset action checks key phrase and reset user's pack
func Reset(msg *tg.Message) { func Reset(msg *tg.Message) {
T, err := i18n.SwitchTo(msg.From.LanguageCode) t, err := i18n.SwitchTo(msg.From.LanguageCode)
errors.Check(err) errors.Check(err)
err = db.ChangeUserState(msg.From.ID, models.StateNone) err = db.DB.ChangeUserState(msg.From, models.StateNone)
errors.Check(err) errors.Check(err)
_, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping) _, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping)
errors.Check(err) errors.Check(err)
if !strings.EqualFold(msg.Text, T("key_phrase")) { if !strings.EqualFold(msg.Text, t("key_phrase")) {
reply := tg.NewMessage(msg.Chat.ID, T("error_reset_phrase")) reply := tg.NewMessage(msg.Chat.ID, t("error_reset_phrase"))
reply.ParseMode = tg.ModeMarkdown reply.ParseMode = tg.StyleMarkdown
reply.ReplyMarkup = helpers.MenuKeyboard(T) reply.ReplyMarkup = utils.MenuKeyboard(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)
return return
} }
err = db.ResetUser(msg.From.ID) err = db.DB.ResetUser(msg.From)
errors.Check(err) errors.Check(err)
reply := tg.NewMessage(msg.Chat.ID, T("success_reset")) reply := tg.NewMessage(msg.Chat.ID, t("success_reset"))
reply.ParseMode = tg.ModeMarkdown reply.ParseMode = tg.StyleMarkdown
reply.ReplyMarkup = helpers.MenuKeyboard(T) reply.ReplyMarkup = utils.MenuKeyboard(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)
} }

View File

@ -1,19 +1,11 @@
package bot package bot
import ( import tg "gitlab.com/toby3d/telegram"
"github.com/toby3d/MyPackBot/internal/config"
"github.com/toby3d/MyPackBot/internal/errors"
tg "github.com/toby3d/telegram"
)
// Bot is a main object of Telegram bot // Bot is a main object of Telegram bot
var Bot *tg.Bot var Bot *tg.Bot
// New just create new bot by configuration credentials // New just create new bot by configuration credentials
func New() { func New(accessToken string) (bot *tg.Bot, err error) {
accessToken, err := config.Config.String("telegram.token") return tg.New(accessToken)
errors.Check(err)
Bot, err = tg.NewBot(accessToken)
errors.Check(err)
} }

View File

@ -2,34 +2,34 @@ package commands
import ( import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/helpers" "gitlab.com/toby3d/mypackbot/internal/i18n"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/models"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/utils"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Add command prepare user for adding some stickers or sets to his pack // Add command prepare user for adding some stickers or sets to his pack
func Add(msg *tg.Message, pack bool) { func Add(msg *tg.Message, pack bool) {
T, err := i18n.SwitchTo(msg.From.LanguageCode) t, err := i18n.SwitchTo(msg.From.LanguageCode)
errors.Check(err) errors.Check(err)
_, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping) _, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping)
errors.Check(err) errors.Check(err)
reply := tg.NewMessage(msg.Chat.ID, T("reply_add_sticker")) reply := tg.NewMessage(msg.Chat.ID, t("reply_add_sticker"))
reply.ParseMode = tg.ModeMarkdown reply.ParseMode = tg.StyleMarkdown
reply.ReplyMarkup = helpers.CancelButton(T) reply.ReplyMarkup = utils.CancelButton(t)
err = db.ChangeUserState(msg.From.ID, models.StateAddSticker) err = db.DB.ChangeUserState(msg.From, models.StateAddSticker)
errors.Check(err) errors.Check(err)
if pack { if pack {
reply.Text = T("reply_add_pack") reply.Text = t("reply_add_pack")
err = db.ChangeUserState(msg.From.ID, models.StateAddPack) err = db.DB.ChangeUserState(msg.From, models.StateAddPack)
errors.Check(err) errors.Check(err)
} }

View File

@ -1,21 +1,21 @@
package commands package commands
import ( import (
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/helpers" "gitlab.com/toby3d/mypackbot/internal/i18n"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/models"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/utils"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Cancel just cancel current user operation // Cancel just cancel current user operation
func Cancel(msg *tg.Message) { func Cancel(msg *tg.Message) {
T, err := i18n.SwitchTo(msg.From.LanguageCode) t, err := i18n.SwitchTo(msg.From.LanguageCode)
errors.Check(err) errors.Check(err)
state, err := db.UserState(msg.From.ID) state, err := db.DB.GetUserState(msg.From)
errors.Check(err) errors.Check(err)
_, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping) _, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping)
@ -24,24 +24,24 @@ func Cancel(msg *tg.Message) {
var text string var text string
switch state { switch state {
case models.StateAddSticker: case models.StateAddSticker:
text = T("cancel_add_sticker") text = t("cancel_add_sticker")
case models.StateAddPack: case models.StateAddPack:
text = T("cancel_add_pack") text = t("cancel_add_pack")
case models.StateDeleteSticker: case models.StateDeleteSticker:
text = T("cancel_del_sticker") text = t("cancel_del_sticker")
case models.StateDeletePack: case models.StateDeletePack:
text = T("cancel_del_pack") text = t("cancel_del_pack")
case models.StateReset: case models.StateReset:
text = T("cancel_reset") text = t("cancel_reset")
default: default:
text = T("cancel_error") text = t("cancel_error")
} }
err = db.ChangeUserState(msg.From.ID, models.StateNone) err = db.DB.ChangeUserState(msg.From, models.StateNone)
errors.Check(err) errors.Check(err)
reply := tg.NewMessage(msg.Chat.ID, text) reply := tg.NewMessage(msg.Chat.ID, text)
reply.ReplyMarkup = helpers.MenuKeyboard(T) reply.ReplyMarkup = utils.MenuKeyboard(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)

View File

@ -2,29 +2,29 @@ package commands
import ( import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/models"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Command check's got user command // Command check's got user command
func Command(msg *tg.Message) { func Command(msg *tg.Message) {
log.Ln("command:", msg.Command()) log.Ln("command:", msg.Command())
switch { switch {
case msg.IsCommand(models.CommandStart): case msg.IsCommandEqual(tg.CommandStart):
Start(msg) Start(msg)
case msg.IsCommand(models.CommandHelp): case msg.IsCommandEqual(tg.CommandHelp):
Help(msg) Help(msg)
case msg.IsCommand(models.CommandAddSticker): case msg.IsCommandEqual(models.CommandAddSticker):
Add(msg, false) Add(msg, false)
case msg.IsCommand(models.CommandAddPack): case msg.IsCommandEqual(models.CommandAddPack):
Add(msg, true) Add(msg, true)
case msg.IsCommand(models.CommandDeleteSticker): case msg.IsCommandEqual(models.CommandDeleteSticker):
Delete(msg, false) Delete(msg, false)
case msg.IsCommand(models.CommandDeletePack): case msg.IsCommandEqual(models.CommandDeletePack):
Delete(msg, true) Delete(msg, true)
case msg.IsCommand(models.CommandReset): case msg.IsCommandEqual(models.CommandReset):
Reset(msg) Reset(msg)
case msg.IsCommand(models.CommandCancel): case msg.IsCommandEqual(models.CommandCancel):
Cancel(msg) Cancel(msg)
} }
} }

View File

@ -1,49 +1,49 @@
package commands package commands
import ( import (
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/helpers" "gitlab.com/toby3d/mypackbot/internal/i18n"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/models"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/utils"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Delete prepare user to remove some stickers or sets from his pack // Delete prepare user to remove some stickers or sets from his pack
func Delete(msg *tg.Message, pack bool) { func Delete(msg *tg.Message, pack bool) {
T, err := i18n.SwitchTo(msg.From.LanguageCode) t, err := i18n.SwitchTo(msg.From.LanguageCode)
errors.Check(err) errors.Check(err)
_, total, err := db.UserStickers(msg.From.ID, 0, "") stickers, err := db.DB.GetUserStickers(msg.From, &tg.InlineQuery{})
errors.Check(err) errors.Check(err)
_, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping) _, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping)
errors.Check(err) errors.Check(err)
if total <= 0 { if len(stickers) <= 0 {
err = db.ChangeUserState(msg.From.ID, models.StateNone) err = db.DB.ChangeUserState(msg.From, models.StateNone)
errors.Check(err) errors.Check(err)
reply := tg.NewMessage(msg.Chat.ID, T("error_empty_del")) reply := tg.NewMessage(msg.Chat.ID, t("error_empty_del"))
reply.ReplyMarkup = helpers.MenuKeyboard(T) reply.ReplyMarkup = utils.MenuKeyboard(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)
return return
} }
reply := tg.NewMessage(msg.Chat.ID, T("reply_del_sticker")) reply := tg.NewMessage(msg.Chat.ID, t("reply_del_sticker"))
reply.ParseMode = tg.ModeMarkdown reply.ParseMode = tg.StyleMarkdown
reply.ReplyMarkup = helpers.CancelButton(T) reply.ReplyMarkup = utils.CancelButton(t)
err = db.ChangeUserState(msg.From.ID, models.StateDeleteSticker) err = db.DB.ChangeUserState(msg.From, models.StateDeleteSticker)
errors.Check(err) errors.Check(err)
if pack { if pack {
err = db.ChangeUserState(msg.From.ID, models.StateDeletePack) err = db.DB.ChangeUserState(msg.From, models.StateDeletePack)
errors.Check(err) errors.Check(err)
reply.Text = T("reply_del_pack") reply.Text = t("reply_del_pack")
} }
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
@ -52,8 +52,8 @@ func Delete(msg *tg.Message, pack bool) {
_, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping) _, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping)
errors.Check(err) errors.Check(err)
reply = tg.NewMessage(msg.Chat.ID, T("reply_switch_button")) reply = tg.NewMessage(msg.Chat.ID, t("reply_switch_button"))
reply.ReplyMarkup = helpers.SwitchButton(T) reply.ReplyMarkup = utils.SwitchButton(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)
} }

View File

@ -1,39 +1,39 @@
package commands package commands
import ( import (
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/helpers" "gitlab.com/toby3d/mypackbot/internal/i18n"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/models"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/utils"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Help just send instructions about bot usage // Help just send instructions about bot usage
func Help(msg *tg.Message) { func Help(msg *tg.Message) {
T, err := i18n.SwitchTo(msg.From.LanguageCode) t, err := i18n.SwitchTo(msg.From.LanguageCode)
errors.Check(err) errors.Check(err)
err = db.ChangeUserState(msg.From.ID, models.StateNone) err = db.DB.ChangeUserState(msg.From, models.StateNone)
errors.Check(err) errors.Check(err)
_, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping) _, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping)
errors.Check(err) errors.Check(err)
reply := tg.NewMessage( reply := tg.NewMessage(
msg.Chat.ID, T("reply_help", map[string]interface{}{ msg.Chat.ID, t("reply_help", map[string]interface{}{
"AddStickerCommand": models.CommandAddSticker, "AddStickerCommand": models.CommandAddSticker,
"AddPackCommand": models.CommandAddPack, "AddPackCommand": models.CommandAddPack,
"DeleteStickerCommand": models.CommandDeleteSticker, "DeleteStickerCommand": models.CommandDeleteSticker,
"DeletePackCommand": models.CommandDeletePack, "DeletePackCommand": models.CommandDeletePack,
"ResetCommand": models.CommandReset, "ResetCommand": models.CommandReset,
"CancelCommand": models.CommandCancel, "CancelCommand": models.CommandCancel,
"Username": bot.Bot.Self.Username, "Username": bot.Bot.Username,
}), }),
) )
reply.ParseMode = tg.ModeMarkdown reply.ParseMode = tg.StyleMarkdown
reply.ReplyMarkup = helpers.MenuKeyboard(T) reply.ReplyMarkup = utils.MenuKeyboard(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)

View File

@ -1,47 +1,47 @@
package commands package commands
import ( import (
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/helpers" "gitlab.com/toby3d/mypackbot/internal/i18n"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/models"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/utils"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Reset prepare user to reset his pack // Reset prepare user to reset his pack
func Reset(msg *tg.Message) { func Reset(msg *tg.Message) {
T, err := i18n.SwitchTo(msg.From.LanguageCode) t, err := i18n.SwitchTo(msg.From.LanguageCode)
errors.Check(err) errors.Check(err)
_, total, err := db.UserStickers(msg.From.ID, 0, "") stickers, err := db.DB.GetUserStickers(msg.From, &tg.InlineQuery{})
errors.Check(err) errors.Check(err)
_, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping) _, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping)
errors.Check(err) errors.Check(err)
if total <= 0 { if len(stickers) <= 0 {
err = db.ChangeUserState(msg.From.ID, models.StateNone) err = db.DB.ChangeUserState(msg.From, models.StateNone)
errors.Check(err) errors.Check(err)
reply := tg.NewMessage(msg.Chat.ID, T("error_already_reset")) reply := tg.NewMessage(msg.Chat.ID, t("error_already_reset"))
reply.ParseMode = tg.ModeMarkdown reply.ParseMode = tg.StyleMarkdown
reply.ReplyMarkup = helpers.MenuKeyboard(T) reply.ReplyMarkup = utils.MenuKeyboard(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)
return return
} }
err = db.ChangeUserState(msg.From.ID, models.StateReset) err = db.DB.ChangeUserState(msg.From, models.StateReset)
errors.Check(err) errors.Check(err)
reply := tg.NewMessage(msg.Chat.ID, T("reply_reset", map[string]interface{}{ reply := tg.NewMessage(msg.Chat.ID, t("reply_reset", map[string]interface{}{
"KeyPhrase": T("key_phrase"), "KeyPhrase": t("key_phrase"),
"CancelCommand": models.CommandCancel, "CancelCommand": models.CommandCancel,
})) }))
reply.ParseMode = tg.ModeMarkdown reply.ParseMode = tg.StyleMarkdown
reply.ReplyMarkup = helpers.CancelButton(T) reply.ReplyMarkup = utils.CancelButton(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)
} }

View File

@ -4,18 +4,18 @@ import (
"strings" "strings"
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/helpers" "gitlab.com/toby3d/mypackbot/internal/i18n"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/models"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/utils"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Start just send introduction about bot to user // Start just send introduction about bot to user
func Start(msg *tg.Message) { func Start(msg *tg.Message) {
err := db.ChangeUserState(msg.From.ID, models.StateNone) err := db.DB.ChangeUserState(msg.From, models.StateNone)
errors.Check(err) errors.Check(err)
_, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping) _, err = bot.Bot.SendChatAction(msg.Chat.ID, tg.ActionTyping)
@ -23,24 +23,24 @@ func Start(msg *tg.Message) {
if msg.HasCommandArgument() { if msg.HasCommandArgument() {
log.Ln("Received a", msg.Command(), "command with", msg.CommandArgument(), "argument") log.Ln("Received a", msg.Command(), "command with", msg.CommandArgument(), "argument")
if strings.EqualFold(msg.CommandArgument(), models.CommandHelp) { if strings.EqualFold(msg.CommandArgument(), tg.CommandHelp) {
Help(msg) Help(msg)
return return
} }
} }
T, err := i18n.SwitchTo(msg.From.LanguageCode) t, err := i18n.SwitchTo(msg.From.LanguageCode)
errors.Check(err) errors.Check(err)
reply := tg.NewMessage( reply := tg.NewMessage(
msg.Chat.ID, msg.Chat.ID,
T("reply_start", map[string]interface{}{ t("reply_start", map[string]interface{}{
"Username": bot.Bot.Self.Username, "Username": bot.Bot.Username,
"ID": bot.Bot.Self.ID, "ID": bot.Bot.ID,
}), }),
) )
reply.ParseMode = tg.ModeMarkdown reply.ParseMode = tg.StyleMarkdown
reply.ReplyMarkup = helpers.MenuKeyboard(T) reply.ReplyMarkup = utils.MenuKeyboard(t)
_, err = bot.Bot.SendMessage(reply) _, err = bot.Bot.SendMessage(reply)
errors.Check(err) errors.Check(err)

View File

@ -1,23 +1,17 @@
package config package config
import ( import "github.com/spf13/viper"
"github.com/olebedev/config"
"github.com/toby3d/MyPackBot/internal/errors"
)
var ( var Config *viper.Viper
// Config is a main object of preloaded configuration YAML
Config *config.Config
// ChannelID is a announcements channel ID
ChannelID int64
)
// Open just open configuration file for parsing some data in other functions // Open just open configuration file for parsing some data in other functions
func Open(path string) { func Open(path string) (*viper.Viper, error) {
var err error cfg := viper.New()
Config, err = config.ParseYamlFile(path)
errors.Check(err)
ChannelID = int64(Config.UInt("telegram.channel")) cfg.AddConfigPath(path)
cfg.SetConfigName("config")
cfg.SetConfigType("yaml")
err := cfg.ReadInConfig()
return cfg, err
} }

View File

@ -5,23 +5,24 @@ import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/tidwall/buntdb" "github.com/tidwall/buntdb"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/models"
tg "gitlab.com/toby3d/telegram"
) )
// AddSticker add sticker FileID, Emoji and SetName meta for UserID // AddSticker add sticker FileID, Emoji and SetName meta for UserID
func AddSticker(userID int, setName, fileID, emoji string) (bool, error) { func (db *DataBase) AddSticker(user *tg.User, sticker *tg.Sticker) (bool, error) {
log.Ln("Trying to add", fileID, "sticker from", userID, "user") log.Ln("Trying to add", sticker.FileID, "sticker from", user.ID, "user")
if setName == "" { if sticker.SetName == "" {
setName = models.SetUploaded sticker.SetName = models.SetUploaded
} }
var exists bool var exists bool
err := DB.Update(func(tx *buntdb.Tx) error { err := db.Update(func(tx *buntdb.Tx) error {
var err error var err error
_, exists, err = tx.Set( _, exists, err = tx.Set(
fmt.Sprint("user:", userID, ":set:", setName, ":sticker:", fileID), // key fmt.Sprint("user:", user.ID, ":set:", sticker.SetName, ":sticker:", sticker.FileID), // key
emoji, // value sticker.Emoji, // value
nil, // options nil, // options
) )
if err == buntdb.ErrIndexExists { if err == buntdb.ErrIndexExists {
exists = true exists = true

View File

@ -5,13 +5,14 @@ import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/tidwall/buntdb" "github.com/tidwall/buntdb"
tg "gitlab.com/toby3d/telegram"
) )
// ChangeUserState change current user state on input state. // ChangeUserState change current user state on input state.
func ChangeUserState(userID int, state string) error { func (db *DataBase) ChangeUserState(user *tg.User, state string) error {
log.Ln("Trying to change", userID, "state to", state) log.Ln("Trying to change", user.ID, "state to", state)
return DB.Update(func(tx *buntdb.Tx) error { return db.Update(func(tx *buntdb.Tx) error {
_, _, err := tx.Set(fmt.Sprint("user:", userID, ":state"), state, nil) _, _, err := tx.Set(fmt.Sprint("user:", user.ID, ":state"), state, nil)
return err return err
}) })
} }

View File

@ -6,43 +6,43 @@ import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/tidwall/buntdb" "github.com/tidwall/buntdb"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/models"
tg "gitlab.com/toby3d/telegram"
) )
// DeletePack remove all keys for UserID which contains input SetName // DeletePack remove all keys for UserID which contains input SetName
func DeletePack(userID int, setName string) (bool, error) { func (db *DataBase) DeletePack(user *tg.User, sticker *tg.Sticker) (bool, error) {
log.Ln("Trying to remove all", setName, "sticker from", userID, "user") log.Ln("Trying to remove all", sticker.SetName, "sticker from", user.ID, "user")
if setName == "" { if sticker.SetName == "" {
setName = models.SetUploaded sticker.SetName = models.SetUploaded
} }
var fileIDs []string var ids []string
err := DB.View(func(tx *buntdb.Tx) error { err := db.View(func(tx *buntdb.Tx) error {
return tx.AscendKeys( return tx.AscendKeys(
fmt.Sprint("user:", userID, ":set:", setName, ":*"), fmt.Sprint("user:", user.ID, ":set:", sticker.SetName, ":*"),
func(key, val string) bool { func(key, val string) bool {
keys := strings.Split(key, ":") keys := strings.Split(key, ":")
fileIDs = append(fileIDs, keys[5]) ids = append(ids, keys[5])
return true return true
}, },
) )
}) })
if len(fileIDs) == 0 { if len(ids) == 0 {
return true, nil return true, nil
} }
for _, fileID := range fileIDs { for _, id := range ids {
var notExist bool var notExist bool
notExist, err = DeleteSticker(userID, setName, fileID) notExist, err = db.DeleteSticker(user, &tg.Sticker{FileID: id})
if err != nil { if err != nil {
return notExist, err return notExist, err
} }
} }
switch err { if err == buntdb.ErrNotFound {
case buntdb.ErrNotFound: log.Ln(user.ID, "not found")
log.Ln(userID, "not found")
return true, nil return true, nil
} }

View File

@ -5,25 +5,25 @@ import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/tidwall/buntdb" "github.com/tidwall/buntdb"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/models"
tg "gitlab.com/toby3d/telegram"
) )
// DeleteSticker just remove specified sticker key from database. // DeleteSticker just remove specified sticker key from database.
func DeleteSticker(userID int, setName, fileID string) (bool, error) { func (db *DataBase) DeleteSticker(user *tg.User, sticker *tg.Sticker) (bool, error) {
log.Ln("Trying to remove", fileID, "sticker from", userID, "user") log.Ln("Trying to remove", sticker.FileID, "sticker from", user.ID, "user")
if setName == "" { if sticker.SetName == "" {
setName = models.SetUploaded sticker.SetName = models.SetUploaded
} }
err := DB.Update(func(tx *buntdb.Tx) error { err := db.Update(func(tx *buntdb.Tx) error {
_, err := tx.Delete( _, err := tx.Delete(
fmt.Sprint("user:", userID, ":set:", setName, ":sticker:", fileID), fmt.Sprint("user:", user.ID, ":set:", sticker.SetName, ":sticker:", sticker.FileID),
) )
return err return err
}) })
if err == buntdb.ErrNotFound { if err == buntdb.ErrNotFound {
log.Ln(userID, "not found, create new one") log.Ln(user.ID, "not found, create new one")
return true, nil return true, nil
} }

View File

@ -0,0 +1,29 @@
package db
import (
"fmt"
log "github.com/kirillDanshin/dlog"
"github.com/tidwall/buntdb"
"gitlab.com/toby3d/mypackbot/internal/models"
tg "gitlab.com/toby3d/telegram"
)
// UserState return current state for UserID
func (db *DataBase) GetUserState(user *tg.User) (string, error) {
log.Ln("Trying to get", user.ID, "state")
var state string
err := db.View(func(tx *buntdb.Tx) error {
var err error
state, err = tx.Get(fmt.Sprint("user:", user.ID, ":state"))
return err
})
if err == buntdb.ErrNotFound {
log.Ln(user.ID, "not found, create new one")
if err = db.ChangeUserState(user, models.StateNone); err != nil {
return state, err
}
}
return state, err
}

View File

@ -0,0 +1,55 @@
package db
import (
"fmt"
"strconv"
"strings"
log "github.com/kirillDanshin/dlog"
"github.com/tidwall/buntdb"
tg "gitlab.com/toby3d/telegram"
)
// GetUserStickers return array of saved stickers for input UserID and his total count
func (db *DataBase) GetUserStickers(user *tg.User, query *tg.InlineQuery) ([]string, error) {
log.Ln("Trying to get", user.ID, "stickers")
var i int
var stickers []string
offset, _ := strconv.Atoi(query.Offset)
offset *= 50
err := db.View(func(tx *buntdb.Tx) error {
return tx.AscendKeys(
fmt.Sprint("user:", user.ID, ":set:*"), // index
func(key, val string) bool { // iterator
subKeys := strings.Split(key, ":")
if subKeys[1] != strconv.Itoa(user.ID) {
return true
}
if len(stickers) == 50 {
return false
}
i++
if i < offset {
return true
}
if query.Query != "" && !strings.Contains(query.Query, val) {
return true
}
stickers = append(stickers, subKeys[5])
return true
},
)
})
if err == buntdb.ErrNotFound {
log.Ln("Not found stickers")
return nil, nil
}
return stickers, err
}

View File

@ -8,10 +8,10 @@ import (
"github.com/tidwall/buntdb" "github.com/tidwall/buntdb"
) )
// Users return array of all available UserID in database // GetUsers return array of all available UserID in database
func Users() ([]int, error) { func (db *DataBase) GetUsers() ([]int, error) {
var users []int var users []int
err := DB.View(func(tx *buntdb.Tx) error { err := db.View(func(tx *buntdb.Tx) error {
return tx.AscendKeys( return tx.AscendKeys(
"user:*:state", "user:*:state",
func(key, val string) bool { func(key, val string) bool {

View File

@ -3,18 +3,16 @@ package db
import ( import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/tidwall/buntdb" "github.com/tidwall/buntdb"
"github.com/toby3d/MyPackBot/internal/errors"
) )
type DataBase struct{ *buntdb.DB }
// DB is a main object of current database connection // DB is a main object of current database connection
var DB *buntdb.DB var DB *DataBase
// Open just open connection to database for work // Open just open connection to database for work
func Open(path string) { func Open(path string) (*DataBase, error) {
log.Ln("Open database file...") log.Ln("Open database file...")
go func() { db, err := buntdb.Open(path)
var err error return &DataBase{db}, err
DB, err = buntdb.Open(path)
errors.Check(err)
}()
} }

View File

@ -7,18 +7,19 @@ import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/tidwall/buntdb" "github.com/tidwall/buntdb"
tg "gitlab.com/toby3d/telegram"
) )
// ResetUser just drop out all stickers keys for input UserID // ResetUser just drop out all stickers keys for input UserID
func ResetUser(userID int) error { func (db *DataBase) ResetUser(user *tg.User) error {
log.Ln("Trying reset all stickers of", userID, "user") log.Ln("Trying reset all stickers of", user.ID, "user")
return DB.Update(func(tx *buntdb.Tx) error { return db.Update(func(tx *buntdb.Tx) error {
var keys []string var keys []string
if err := tx.AscendKeys( if err := tx.AscendKeys(
fmt.Sprint("user:", userID, ":set:*"), // index fmt.Sprint("user:", user.ID, ":set:*"), // index
func(key, val string) bool { // iterator func(key, val string) bool { // iterator
subKeys := strings.Split(key, ":") subKeys := strings.Split(key, ":")
if subKeys[1] == strconv.Itoa(userID) { if subKeys[1] == strconv.Itoa(user.ID) {
keys = append(keys, key) keys = append(keys, key)
} }
return true return true

View File

@ -5,23 +5,23 @@ import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/tidwall/buntdb" "github.com/tidwall/buntdb"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/models"
tg "gitlab.com/toby3d/telegram"
) )
// UserState return current state for UserID // UserState return current state for UserID
func UserState(userID int) (string, error) { func (db *DataBase) UserState(usr *tg.User) (string, error) {
log.Ln("Trying to get", userID, "state") log.Ln("Trying to get", usr.ID, "state")
var state string var state string
err := DB.View(func(tx *buntdb.Tx) error { err := DB.View(func(tx *buntdb.Tx) error {
var err error var err error
state, err = tx.Get(fmt.Sprint("user:", userID, ":state")) state, err = tx.Get(fmt.Sprint("user:", usr.ID, ":state"))
return err return err
}) })
switch err { if err == buntdb.ErrNotFound {
case buntdb.ErrNotFound: log.Ln(usr.ID, "not found, create new one")
log.Ln(userID, "not found, create new one") if err = db.ChangeUserState(usr, models.StateNone); err != nil {
if err = ChangeUserState(userID, models.StateNone); err != nil {
return state, err return state, err
} }
} }

View File

@ -1,54 +0,0 @@
package db
import (
"fmt"
"strconv"
"strings"
log "github.com/kirillDanshin/dlog"
"github.com/tidwall/buntdb"
)
// UserStickers return array of saved stickers for input UserID and his total count
func UserStickers(userID, offset int, query string) ([]string, int, error) {
log.Ln("Trying to get", userID, "stickers")
var total, count int
var stickers []string
offset = offset * 50
err := DB.View(func(tx *buntdb.Tx) error {
return tx.AscendKeys(
fmt.Sprint("user:", userID, ":set:*"), // index
func(key, val string) bool { // iterator
subKeys := strings.Split(key, ":")
if subKeys[1] != strconv.Itoa(userID) {
return true
}
total++
if count >= 51 {
return true
}
if total < offset {
return true
}
if query != "" && !strings.Contains(query, val) {
return true
}
count++
stickers = append(stickers, subKeys[5])
return true
},
)
})
if err == buntdb.ErrNotFound {
log.Ln("Not found stickers")
return nil, total, nil
}
return stickers, total, err
}

View File

@ -1,23 +0,0 @@
package helpers
import (
"github.com/nicksnyder/go-i18n/i18n"
tg "github.com/toby3d/telegram"
)
// MenuKeyboard helper just generate ReplyMarkup with menu buttons
func MenuKeyboard(T i18n.TranslateFunc) *tg.ReplyKeyboardMarkup {
return tg.NewReplyKeyboardMarkup(
tg.NewReplyKeyboardRow(
tg.NewReplyKeyboardButton(T("button_add_sticker")),
tg.NewReplyKeyboardButton(T("button_add_pack")),
),
tg.NewReplyKeyboardRow(
tg.NewReplyKeyboardButton(T("button_del_sticker")),
tg.NewReplyKeyboardButton(T("button_del_pack")),
),
tg.NewReplyKeyboardRow(
tg.NewReplyKeyboardButton(T("button_reset")),
),
)
}

View File

@ -2,12 +2,12 @@ package i18n
import ( import (
"github.com/nicksnyder/go-i18n/i18n" "github.com/nicksnyder/go-i18n/i18n"
"github.com/toby3d/MyPackBot/internal/models" "gitlab.com/toby3d/mypackbot/internal/models"
) )
// SwitchTo try load locales by input language codes and return TranslateFunc // SwitchTo try load locales by input language codes and return TranslateFunc
func SwitchTo(codes ...string) (T i18n.TranslateFunc, err error) { func SwitchTo(codes ...string) (t i18n.TranslateFunc, err error) {
codes = append(codes, models.LanguageFallback) codes = append(codes, models.LanguageFallback)
T, err = i18n.Tfunc(codes[0], codes[1:]...) t, err = i18n.Tfunc(codes[0], codes[1:]...)
return return
} }

View File

@ -3,31 +3,31 @@ package messages
import ( import (
"strings" "strings"
"github.com/toby3d/MyPackBot/internal/actions" "gitlab.com/toby3d/mypackbot/internal/actions"
"github.com/toby3d/MyPackBot/internal/commands" "gitlab.com/toby3d/mypackbot/internal/commands"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/i18n"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Message checks user message on response, stickers, reset key phrase, else do // Message checks user message on response, stickers, reset key phrase, else do
// Actions // Actions
func Message(msg *tg.Message) { func Message(msg *tg.Message) {
T, err := i18n.SwitchTo(msg.From.LanguageCode) t, err := i18n.SwitchTo(msg.From.LanguageCode)
errors.Check(err) errors.Check(err)
switch { switch {
case strings.EqualFold(msg.Text, T("button_add_sticker")): case strings.EqualFold(msg.Text, t("button_add_sticker")):
commands.Add(msg, false) commands.Add(msg, false)
case strings.EqualFold(msg.Text, T("button_add_pack")): case strings.EqualFold(msg.Text, t("button_add_pack")):
commands.Add(msg, true) commands.Add(msg, true)
case strings.EqualFold(msg.Text, T("button_del_sticker")): case strings.EqualFold(msg.Text, t("button_del_sticker")):
commands.Delete(msg, false) commands.Delete(msg, false)
case strings.EqualFold(msg.Text, T("button_del_pack")): case strings.EqualFold(msg.Text, t("button_del_pack")):
commands.Delete(msg, true) commands.Delete(msg, true)
case strings.EqualFold(msg.Text, T("button_reset")): case strings.EqualFold(msg.Text, t("button_reset")):
commands.Reset(msg) commands.Reset(msg)
case strings.EqualFold(msg.Text, T("button_cancel")): case strings.EqualFold(msg.Text, t("button_cancel")):
commands.Cancel(msg) commands.Cancel(msg)
default: default:
actions.Action(msg) actions.Action(msg)

View File

@ -1,17 +1,15 @@
package models package models
import tg "github.com/toby3d/telegram" import tg "gitlab.com/toby3d/telegram"
// Commands... represents available and supported bot commands // Commands... represents available and supported bot commands
const ( const (
CommandAddPack = "addPack" CommandAddPack = "addPack"
CommandAddSticker = "addSticker" CommandAddSticker = "addSticker"
CommandCancel = "cancel" CommandCancel = "cancel"
CommandHelp = "help"
CommandDeleteSticker = "delSticker" CommandDeleteSticker = "delSticker"
CommandDeletePack = "delPack" CommandDeletePack = "delPack"
CommandReset = "reset" CommandReset = "reset"
CommandStart = "start"
) )
// State... represents current state of user action // State... represents current state of user action

View File

@ -2,63 +2,67 @@ package updates
import ( import (
"fmt" "fmt"
"net/url"
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/config" "gitlab.com/toby3d/mypackbot/internal/config"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/models"
"github.com/toby3d/MyPackBot/internal/models" tg "gitlab.com/toby3d/telegram"
tg "github.com/toby3d/telegram"
) )
// Channel return webhook or long polling channel with bot updates // Channel return webhook or long polling channel with bot updates
func Channel(webhookMode bool) tg.UpdatesChannel { func Channel(webhookMode bool) (updates tg.UpdatesChannel, err error) {
log.Ln("Preparing channel for updates...") log.Ln("Preparing channel for updates...")
if !webhookMode { if !webhookMode {
log.Ln("Use LongPolling updates") log.Ln("Use LongPolling updates")
info, err := bot.Bot.GetWebhookInfo() var info *tg.WebhookInfo
errors.Check(err) info, err = bot.Bot.GetWebhookInfo()
if err != nil {
return
}
if info.URL != "" { if info.URL != "" {
log.Ln("Deleting webhook...") log.Ln("Deleting webhook...")
_, err := bot.Bot.DeleteWebhook() _, err = bot.Bot.DeleteWebhook()
errors.Check(err) return
} }
return bot.Bot.NewLongPollingChannel(&tg.GetUpdatesParameters{ updates = bot.Bot.NewLongPollingChannel(&tg.GetUpdatesParameters{
Offset: 0, Offset: 0,
Limit: 100, Limit: 100,
Timeout: 60, Timeout: 60,
AllowedUpdates: models.AllowedUpdates, AllowedUpdates: models.AllowedUpdates,
}) })
return
} }
var err error set, err := url.Parse(config.Config.GetString("telegram.webhook.set"))
var set, listen, serve string if err != nil {
set, err = config.Config.String("telegram.webhook.set") return nil, err
errors.Check(err) }
listen, err = config.Config.String("telegram.webhook.listen")
errors.Check(err) listen := config.Config.GetString("telegram.webhook.listen")
serve, err = config.Config.String("telegram.webhook.serve") serve := config.Config.GetString("telegram.webhook.serve")
errors.Check(err)
log.Ln( log.Ln(
"Trying set webhook on address:", "Trying set webhook on address:",
fmt.Sprint(set, listen, bot.Bot.AccessToken), fmt.Sprint(set.String(), bot.Bot.AccessToken),
) )
log.Ln("Creating new webhook...") log.Ln("Creating new webhook...")
webhook := tg.NewWebhook(fmt.Sprint(set, listen, bot.Bot.AccessToken), nil) params := tg.NewWebhook(fmt.Sprint(set, listen, bot.Bot.AccessToken), nil)
webhook.MaxConnections = 40 params.MaxConnections = 40
webhook.AllowedUpdates = models.AllowedUpdates params.AllowedUpdates = models.AllowedUpdates
return bot.Bot.NewWebhookChannel( updates = bot.Bot.NewWebhookChannel(
webhook, // params set,
"", // certFile params, // params
"", // keyFile "", // certFile
set, // set "", // keyFile
fmt.Sprint(listen, bot.Bot.AccessToken), // listen serve, // serve
serve, // serve
) )
return
} }

View File

@ -4,21 +4,22 @@ import (
"time" "time"
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/config" "gitlab.com/toby3d/mypackbot/internal/config"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// ChannelPost checks ChannelPost update for forwarding content to bot users // ChannelPost checks ChannelPost update for forwarding content to bot users
func ChannelPost(post *tg.Message) { func ChannelPost(post *tg.Message) {
if post.Chat.ID != config.ChannelID { channelID := config.Config.GetInt64("telegram.channel")
log.Ln(post.Chat.ID, "!=", config.ChannelID) if post.Chat.ID != channelID {
log.Ln(post.Chat.ID, "!=", channelID)
return return
} }
users, err := db.Users() users, err := db.DB.GetUsers()
errors.Check(err) errors.Check(err)
for i := range users { for i := range users {

View File

@ -4,23 +4,22 @@ import (
"strconv" "strconv"
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/db" "gitlab.com/toby3d/mypackbot/internal/db"
"github.com/toby3d/MyPackBot/internal/errors" "gitlab.com/toby3d/mypackbot/internal/errors"
"github.com/toby3d/MyPackBot/internal/helpers" "gitlab.com/toby3d/mypackbot/internal/i18n"
"github.com/toby3d/MyPackBot/internal/i18n" "gitlab.com/toby3d/mypackbot/internal/utils"
"github.com/toby3d/MyPackBot/internal/models" tg "gitlab.com/toby3d/telegram"
tg "github.com/toby3d/telegram"
) )
// InlineQuery checks InlineQuery updates for answer with personal results // InlineQuery checks InlineQuery updates for answer with personal results
func InlineQuery(inlineQuery *tg.InlineQuery) { func InlineQuery(inlineQuery *tg.InlineQuery) {
fixedQuery, err := helpers.FixEmoji(inlineQuery.Query) fixedQuery, err := utils.FixEmoji(inlineQuery.Query)
if err == nil { if err == nil {
inlineQuery.Query = fixedQuery inlineQuery.Query = fixedQuery
} }
answer := &tg.AnswerInlineQueryParameters{} answer := new(tg.AnswerInlineQueryParameters)
answer.InlineQueryID = inlineQuery.ID answer.InlineQueryID = inlineQuery.ID
answer.CacheTime = 1 answer.CacheTime = 1
answer.IsPersonal = true answer.IsPersonal = true
@ -32,7 +31,7 @@ func InlineQuery(inlineQuery *tg.InlineQuery) {
} }
log.Ln("Let's preparing answer...") log.Ln("Let's preparing answer...")
T, err := i18n.SwitchTo(inlineQuery.From.LanguageCode) t, err := i18n.SwitchTo(inlineQuery.From.LanguageCode)
errors.Check(err) errors.Check(err)
log.Ln("INLINE OFFSET:", inlineQuery.Offset) log.Ln("INLINE OFFSET:", inlineQuery.Offset)
@ -43,51 +42,40 @@ func InlineQuery(inlineQuery *tg.InlineQuery) {
errors.Check(err) errors.Check(err)
offset++ offset++
stickers, packSize, err := db.UserStickers( stickers, err := db.DB.GetUserStickers(
inlineQuery.From.ID, offset, inlineQuery.Query, inlineQuery.From,
&tg.InlineQuery{
Offset: strconv.Itoa(offset),
Query: inlineQuery.Query,
},
) )
errors.Check(err) errors.Check(err)
totalStickers := len(stickers) if len(stickers) == 0 {
if totalStickers == 0 { if offset == 0 && inlineQuery.Query != "" {
if offset == 0 { // If search stickers by emoji return 0 results
if inlineQuery.Query != "" { answer.SwitchPrivateMessageText = t(
// If search stickers by emoji return 0 results "button_inline_nothing", map[string]interface{}{
answer.SwitchPrivateMessageText = T( "Query": inlineQuery.Query,
"button_inline_nothing", map[string]interface{}{ },
"Query": inlineQuery.Query, )
},
) answer.SwitchPrivateMessageParameter = tg.CommandHelp
answer.SwitchPrivateMessageParameter = models.CommandAddSticker
} else {
// If query is empty and get 0 stickers
answer.SwitchPrivateMessageText = T("button_inline_empty")
answer.SwitchPrivateMessageParameter = models.CommandAddSticker
}
answer.Results = nil
} }
answer.Results = nil
} else { } else {
log.Ln("STICKERS FROM REQUEST:", totalStickers) log.Ln("STICKERS FROM REQUEST:", len(stickers))
if totalStickers > 50 { if len(stickers) == 50 {
answer.NextOffset = strconv.Itoa(offset) answer.NextOffset = strconv.Itoa(offset)
log.Ln("NEXT OFFSET:", answer.NextOffset) log.Ln("NEXT OFFSET:", answer.NextOffset)
stickers = stickers[:totalStickers-1]
} }
log.Ln("Stickers after checks:", len(stickers))
var results = make([]interface{}, len(stickers)) var results = make([]interface{}, len(stickers))
for i, sticker := range stickers { for i, sticker := range stickers {
results[i] = tg.NewInlineQueryResultCachedSticker(sticker, sticker) results[i] = tg.NewInlineQueryResultCachedSticker(sticker, sticker)
} }
answer.SwitchPrivateMessageText = T(
"button_inline_search", packSize, map[string]interface{}{
"Count": packSize,
},
)
answer.SwitchPrivateMessageParameter = models.CommandHelp
answer.Results = results answer.Results = results
} }

View File

@ -2,11 +2,11 @@ package updates
import ( import (
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
"github.com/toby3d/MyPackBot/internal/actions" "gitlab.com/toby3d/mypackbot/internal/actions"
"github.com/toby3d/MyPackBot/internal/bot" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/commands" "gitlab.com/toby3d/mypackbot/internal/commands"
"github.com/toby3d/MyPackBot/internal/messages" "gitlab.com/toby3d/mypackbot/internal/messages"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// Message checks Message updates for answer to user commands, replies or sended // Message checks Message updates for answer to user commands, replies or sended

View File

@ -1,15 +1,15 @@
package helpers package utils
import ( import (
"github.com/nicksnyder/go-i18n/i18n" "github.com/nicksnyder/go-i18n/i18n"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// CancelButton helper just generate ReplyMarkup with cancel button // CancelButton helper just generate ReplyMarkup with cancel button
func CancelButton(T i18n.TranslateFunc) *tg.ReplyKeyboardMarkup { func CancelButton(t i18n.TranslateFunc) *tg.ReplyKeyboardMarkup {
return tg.NewReplyKeyboardMarkup( return tg.NewReplyKeyboardMarkup(
tg.NewReplyKeyboardRow( tg.NewReplyKeyboardRow(
tg.NewReplyKeyboardButton(T("button_cancel")), tg.NewReplyKeyboardButton(t("button_cancel")),
), ),
) )
} }

View File

@ -1,4 +1,4 @@
package helpers package utils
import ( import (
"golang.org/x/text/runes" "golang.org/x/text/runes"

View File

@ -0,0 +1,23 @@
package utils
import (
"github.com/nicksnyder/go-i18n/i18n"
tg "gitlab.com/toby3d/telegram"
)
// MenuKeyboard helper just generate ReplyMarkup with menu buttons
func MenuKeyboard(t i18n.TranslateFunc) *tg.ReplyKeyboardMarkup {
return tg.NewReplyKeyboardMarkup(
tg.NewReplyKeyboardRow(
tg.NewReplyKeyboardButton(t("button_add_sticker")),
tg.NewReplyKeyboardButton(t("button_add_pack")),
),
tg.NewReplyKeyboardRow(
tg.NewReplyKeyboardButton(t("button_del_sticker")),
tg.NewReplyKeyboardButton(t("button_del_pack")),
),
tg.NewReplyKeyboardRow(
tg.NewReplyKeyboardButton(t("button_reset")),
),
)
}

View File

@ -1,15 +1,15 @@
package helpers package utils
import ( import (
"github.com/nicksnyder/go-i18n/i18n" "github.com/nicksnyder/go-i18n/i18n"
tg "github.com/toby3d/telegram" tg "gitlab.com/toby3d/telegram"
) )
// SwitchButton helper just generate ReplyMarkup with SelfSwitch button // SwitchButton helper just generate ReplyMarkup with SelfSwitch button
func SwitchButton(T i18n.TranslateFunc) *tg.InlineKeyboardMarkup { func SwitchButton(t i18n.TranslateFunc) *tg.InlineKeyboardMarkup {
return tg.NewInlineKeyboardMarkup( return tg.NewInlineKeyboardMarkup(
tg.NewInlineKeyboardRow( tg.NewInlineKeyboardRow(
tg.NewInlineKeyboardButtonSwitchSelf(T("button_inline_select"), " "), tg.NewInlineKeyboardButtonSwitchSelf(t("button_inline_select"), " "),
), ),
) )
} }

32
main.go
View File

@ -4,8 +4,12 @@ import (
"flag" "flag"
log "github.com/kirillDanshin/dlog" log "github.com/kirillDanshin/dlog"
_ "github.com/toby3d/MyPackBot/init" "gitlab.com/toby3d/mypackbot/internal/bot"
"github.com/toby3d/MyPackBot/internal/updates" "gitlab.com/toby3d/mypackbot/internal/config"
"gitlab.com/toby3d/mypackbot/internal/db"
"gitlab.com/toby3d/mypackbot/internal/errors"
"gitlab.com/toby3d/mypackbot/internal/i18n"
"gitlab.com/toby3d/mypackbot/internal/updates"
) )
var flagWebhook = flag.Bool( var flagWebhook = flag.Bool(
@ -13,11 +17,33 @@ var flagWebhook = flag.Bool(
"enable work via webhooks (required valid certificates)", "enable work via webhooks (required valid certificates)",
) )
// init prepare configuration and other things for successful start
func init() {
log.Ln("Initializing...")
// Preload localization strings
err := i18n.Open("i18n/")
errors.Check(err)
// Preload configuration file
config.Open("configs/config.yaml")
// Open database or create new one
db.Open("stickers.db")
// Create bot with credentials from config
bot.Bot, err = bot.New(config.Config.GetString("telegram.token"))
errors.Check(err)
}
// main function is a general function for work of this bot // main function is a general function for work of this bot
func main() { func main() {
flag.Parse() // Parse flagWebhook flag.Parse() // Parse flagWebhook
for update := range updates.Channel(*flagWebhook) { channel, err := updates.Channel(*flagWebhook)
errors.Check(err)
for update := range channel {
log.D(update) log.D(update)
switch { switch {
case update.IsInlineQuery(): case update.IsInlineQuery():