From 3aa89d551e4d35b4bcc6e89586bb207f45014b9f Mon Sep 17 00:00:00 2001 From: Stefano Salvatori Date: Fri, 1 Jan 2021 12:54:16 +0100 Subject: [PATCH] add webhook support --- .gitignore | 3 +- .travis.yml | 3 +- Dockerfile | 2 +- README.md | 29 +++++++-- configuration.go | 36 +++++++++-- doc/configuration.md | 66 ++++++++++++++++++++ doc/learn.md | 57 ++++++++++++++++++ doc/webhook.md | 0 go.mod | 8 ++- go.sum | 14 +++-- main.go | 34 +++++++++++ main_test.go | 41 ------------- server/server.go | 69 +++++++++++++++++++++ server/server_test.go | 28 +++++++++ zbot.conf | 14 +++-- zbot/zbot.go | 137 +++++++++++++++++++++++++++--------------- zbot/zbot_test.go | 36 +++++++++++ 17 files changed, 462 insertions(+), 115 deletions(-) create mode 100644 doc/configuration.md create mode 100644 doc/learn.md create mode 100644 doc/webhook.md create mode 100644 server/server.go create mode 100644 server/server_test.go diff --git a/.gitignore b/.gitignore index f1503e0..1e39343 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,5 @@ zbot-telegram *.db /venv zbot_dev.conf -plex.py \ No newline at end of file +plex.py +vendor/** \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 1ecd47c..236471b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,8 @@ script: - go test -v github.com/ssalvatori/zbot-telegram/utils -coverprofile=utils.coverprofile - go test -v github.com/ssalvatori/zbot-telegram/user -coverprofile=user.coverprofile - go test -v github.com/ssalvatori/zbot-telegram/db -coverprofile=db.coverprofile - - go test -v github.com/ssalvatori/zbot-telegram/commands -coverprofile=db.coverprofile + - go test -v github.com/ssalvatori/zbot-telegram/commands -coverprofile=commands.coverprofile + - go test -v github.com/ssalvatori/zbot-telegram/server -coverprofile=server.coverprofile - $HOME/gopath/bin/gover - $HOME/gopath/bin/goveralls -coverprofile gover.coverprofile -service travis-ci --ignore=db/mock.go,db/db.go,db/sqlite.go after_success: diff --git a/Dockerfile b/Dockerfile index de9d348..89610f0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ ARG ARCH=amd64 WORKDIR /go/src/app COPY . . -RUN CGO_ENABLED=1 GOOS=${OS} GOARCH=${ARCH} go build -ldflags "-X github.com/ssalvatori/zbot-telegram/zbot.version=`git describe --tags` -X github.com/ssalvatori/zbot-telegram/zbot.buildTime=`TZ=UTC date -u '+%Y-%m-%d %H:%M:%SZ'` -X github.com/ssalvatori/zbot-telegram/zbot.gitHash=`git rev-parse --short HEAD`" -o zbot-telegram-${OS}-${ARCH} +RUN CGO_ENABLED=1 GOOS=${OS} GOARCH=${ARCH} go build -ldflags "-X github.com/ssalvatori/zbot-telegram/zbot.version=`git describe --tags` -X github.com/ssalvatori/zbot-telegram/zbot.buildTime=`TZ=UTC date -u '+%Y-%m-%dT%H:%M:%SZ'` -X github.com/ssalvatori/zbot-telegram/zbot.gitHash=`git rev-parse --short HEAD`" -o zbot-telegram-${OS}-${ARCH} FROM debian:buster-slim diff --git a/README.md b/README.md index 5fa9548..59d5842 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,22 @@ [![Coverage Status](https://coveralls.io/repos/github/ssalvatori/zbot-telegram/badge.svg?branch=master)](https://coveralls.io/github/ssalvatori/zbot-telegram?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/ssalvatori/zbot-telegram)](https://goreportcard.com/report/github.com/ssalvatori/zbot-telegram) + + +## Features + + * Core Learn module [doc/learn](doc/learn.md) + * Run external modules + * Webhook [doc/webhook](doc/webhook.md) + ## Requirements * You need to get an API TOKEN from [BotFather@Telegram](https://core.telegram.org/bots) ## Setup -You **must** set the environment variable **ZBOT_CONFIG_FILE** with the path to the configuration file +You **must** set the **ZBOT_CONFIG_FILE** environment variable with the path to the configuration file * ZBOT_CONFIG_FILE : Path to the configuration file (default ./zbot.conf) -* ZBOT_LOG_LEVEL : Log verbosity (default info) ## Configuration File @@ -24,7 +31,21 @@ zbot: level: false db: engine: sqlite + name: db_name file: path_to_sqlite_file.db + host: 127.0.0.1 + port: 3306 + username: db_username + password: db_password +webhook: + disable: true + port: 13371 + auth: + - channel: channel1 + id: 1234 + token: + - channel: channel2 + token: s commands: learn: disabled: @@ -52,11 +73,11 @@ modules: ## Database Schemas -[GORM](https://gorm.io/index.html), will creat the necessary schemas and migrations +[GORM](https://gorm.io/index.html), will creat all the schemas and migrations ## Development ```bash docker build -t zbot-telegram -f Dockerfile . docker run --rm --name zbot-telegram -v ${PWD}/modules:/app/modules -v ${PWD}/zbot.conf:/app/zbot.conf -e ZBOT_CONFIG_FILE=/app/zbot.conf zbot-telegram:latest -``` +``` \ No newline at end of file diff --git a/configuration.go b/configuration.go index bc0da7d..3e209bf 100644 --- a/configuration.go +++ b/configuration.go @@ -5,7 +5,7 @@ import ( "io/ioutil" log "github.com/sirupsen/logrus" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) /* @@ -17,9 +17,17 @@ type Configuration struct { Level bool `yaml:"level"` } `yaml:"zbot"` Db struct { - Engine string `yaml:"engine"` - File string `yaml:"file"` + Engine string `yaml:"engine"` + File string `yaml:"file"` } `yaml:"db"` + Webhook struct { + Port int `yaml:"port"` + Auth []struct { + Channel string `yaml:"channel"` + ID int64 `yaml:"id,omitempty"` + Token string `yaml:"token,omitempty"` + } `yaml:"auth"` + } `yaml:"webhook"` Commands struct { Learn struct { Disabled []string `yaml:"disabled"` @@ -42,10 +50,23 @@ type Configuration struct { type Configuration struct { Zbot configurationZbot `yaml:"zbot"` Db configurationDb `yaml:"db"` + Webhook configurationWebhook `yaml:"webhook"` Commands configurationCommands `yaml:"commands"` Modules configurationModules `yaml:"modules"` } +type configurationWebhook struct { + Disable bool `yaml:"disable,omitempty"` + Port int `yaml:"port"` + Auth []channel `yaml:"auth"` +} + +type channel struct { + Channel string `yaml:"channel"` + ID int64 `yaml:"id,omitempty"` + Token string `yaml:"token,omitempty"` +} + type configurationCommands struct { Learn configurationLearn `yaml:"learn"` Disabled []string `yaml:"disabled"` @@ -62,8 +83,13 @@ type configurationZbot struct { } type configurationDb struct { - Engine string `yaml:"engine"` - File string `yaml:"file"` + Engine string `yaml:"engine"` + Name string `yaml:"name"` + File string `yaml:"file"` + Host string `yaml:"host"` + Port int `yaml:"port"` + Username string `yaml:"username"` + Password string `yaml:"password"` } type configurationLearn struct { diff --git a/doc/configuration.md b/doc/configuration.md new file mode 100644 index 0000000..5ec1ffe --- /dev/null +++ b/doc/configuration.md @@ -0,0 +1,66 @@ +# Zbot Configuration + +```yaml +zbot: + token: + ignore_duration: 300 + ignore: true + level: false +db: + engine: sqlite + file: path_to_sqlite_file.db +webhook: + disable: true + port: 13371 + auth: + - channel: channel1 + id: 1234 + token: + - channel: channel2 + token: +commands: + learn: + disabled: + - zbot_dev + disabled: + - ignore + - level + - forget +modules: + path: ./modules/ + list: + - key: crypto + file: cypto + description: get some crypto data + - key: test + file: test + description: test module + - key: temp + file: temp.sh + description: get weather info + - key: plex + file: plex2.py + description: get plext information +``` + +## zbot + +## db +```yaml +db: + engine: sqlite + file: path_to_sqlite_file.db +``` +## webhook +```yaml +webhook: + disable: bool // Enable or disable bot webhook (default: false) + port: int // Webhook port (default: 11337) + auth: + - channel: string // Channel name (bot will overwrite it using chat_id information) + id: int64 // Telegram Chat_ID (leave it empty and the bot will try to get it using channel name) + token: string // Token to autenticate request, this should be unique per channel +``` +## commands + +## modules \ No newline at end of file diff --git a/doc/learn.md b/doc/learn.md new file mode 100644 index 0000000..db9c43e --- /dev/null +++ b/doc/learn.md @@ -0,0 +1,57 @@ +# Learn Module + +## Configuiration +This set of modules are enabled by default but they can be disabled in the bot [configuration file](./configuration.md) + +### Learn a *term* +If the term is already in the db an autoincrementa number will be added as a suffix. (term1, term2,...) +``` +!learn [term] [meaning] +``` + +### Get the *meaning* of a *term* +``` +?[term] +``` + +### Get information a *term* +``` +!who [term] +``` + +### Append *meaning* to a *term* +``` +!append [term] [meaning] +``` + +### Get a random *term* +``` +!rand +``` + +### Get last term learned +``` +!last +``` + +### Search similar terms +``` +!search *term* +``` + +### Find terms searching a *text* inside a meaning definition +``` +!find *text* +``` + +### Top (get top [number] terms) +``` +!top [number] +``` + + +### Get total number of terms in db +``` +!stats +``` + diff --git a/doc/webhook.md b/doc/webhook.md new file mode 100644 index 0000000..e69de29 diff --git a/go.mod b/go.mod index 43951d9..0a9ad9e 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,14 @@ go 1.15 require ( github.com/caarlos0/env/v6 v6.4.0 + github.com/mitchellh/mapstructure v1.4.0 github.com/pkg/errors v0.9.1 // indirect github.com/sirupsen/logrus v1.7.0 github.com/stretchr/testify v1.6.1 - golang.org/x/sys v0.0.0-20201218084310-7d0127a74742 // indirect + golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 // indirect gopkg.in/tucnak/telebot.v2 v2.3.5 - gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v2 v2.2.2 + gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 gorm.io/driver/sqlite v1.1.4 - gorm.io/gorm v1.20.8 + gorm.io/gorm v1.20.9 ) diff --git a/go.sum b/go.sum index a6869db..7eda27e 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ= github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= +github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks= +github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -24,20 +26,20 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201218084310-7d0127a74742 h1:+CBz4km/0KPU3RGTwARGh/noP3bEwtHcq+0YcBQM2JQ= -golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 h1:joucsQqXmyBVxViHCPFjG3hx8JzIFSaym3l3MM/Jsdg= +golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/tucnak/telebot.v2 v2.3.5 h1:TdMJTlG8kvepsvZdy/gPeYEBdwKdwFFjH1AQTua9BOU= gopkg.in/tucnak/telebot.v2 v2.3.5/go.mod h1:BgaIIx50PSRS9pG59JH+geT82cfvoJU/IaI5TJdN3v8= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM= gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.8 h1:iToaOdZgjNvlc44NFkxfLa3U9q63qwaxt0FdNCiwOMs= -gorm.io/gorm v1.20.8/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.20.9 h1:M3aIZKXAC1PtPVu9t3WGwkBTE1le5c2telz3I/qjRNg= +gorm.io/gorm v1.20.9/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= diff --git a/main.go b/main.go index 9cd3734..b93e323 100644 --- a/main.go +++ b/main.go @@ -87,6 +87,40 @@ func setup() { zbot.Db = setupDatabase(configuration) zbot.ExternalModules = zbot.ExternalModulesList(configuration.Modules.List) + zbot.Channels = setupChannels(configuration.Webhook.Auth) + + if configuration.Webhook.Disable { + log.Info(fmt.Sprintf("WebServer: disable")) + zbot.Webhook.Enable = false + } else { + zbot.Webhook.Enable = true + log.Info(fmt.Sprintf("WebServer: enable")) + + if len(configuration.Webhook.Auth) == 0 { + log.Fatal("No Webhook.Auth present, exiting now!!") + } + + if configuration.Webhook.Port != 0 { + zbot.Webhook.Port = configuration.Webhook.Port + } + log.Info(fmt.Sprintf("WebServer Port: %d", zbot.Webhook.Port)) + + } + +} + +func setupChannels(configuration []channel) []zbot.Channel { + var channels = []zbot.Channel{} + + for i := range configuration { + channels = append(channels, zbot.Channel{ + ID: configuration[i].ID, + Title: configuration[i].Channel, + AuthToken: configuration[i].Token, + }) + } + + return channels } func init() { diff --git a/main_test.go b/main_test.go index 777a602..646e5fe 100644 --- a/main_test.go +++ b/main_test.go @@ -109,44 +109,3 @@ func TestSetupDatabaseSqLite(t *testing.T) { assert.Equal(t, zbot.DatabaseType, "sqlite", "DataBaseType sqlite OK") assert.IsType(t, &db.ZbotDatabaseSqlite{}, dbInstance) } - -// func TestSetupDatabaseMysql(t *testing.T) { - -// os.Setenv("ZBOT_DATABASE_TYPE", "mysql") -// os.Setenv("ZBOT_MYSQL_HOSTNAME", "localhost") -// os.Setenv("ZBOT_MYSQL_USERNAME", "root") -// os.Setenv("ZBOT_MYSQL_PASSWORD", "pass") -// os.Setenv("ZBOT_MYSQL_DATABASE", "test") -// dbInstance := setupDatabase() -// assert.Equal(t, zbot.DatabaseType, "mysql", "DataBaseType mysql OK") -// assert.IsType(t, &db.ZbotMysqlDatabase{}, dbInstance) -// assert.Equal(t, "root:pass@tcp(localhost:3306)/test", dbInstance.GetConnectionInfo(), "DataBaseType mysql OK") - -// } - -// func TestSetDisabledCommands(t *testing.T) { -// assert.Equal(t, []string{"cmd1", "cmd2", "cmd3", "cmd4"}, SetDisabledCommands("cmd1,cmd2,cmd3, cmd4"), "Set Disabled Commands") -// assert.Equal(t, []string{}, SetDisabledCommands(""), "No commands") -// } - -// func TestSetupFlags(t *testing.T) { -// os.Unsetenv("ZBOT_FLAG_ACTIVATE_IGNORE") -// setupFlags() -// assert.Equal(t, zbot.Flags.Ignore, false, "Ignore Users Off") - -// os.Setenv("ZBOT_FLAG_ACTIVATE_IGNORE", "true") -// setupFlags() -// assert.Equal(t, zbot.Flags.Ignore, true, "Ignore Users ON") - -// os.Unsetenv("ZBOT_FLAG_ACTIVATE_LEVELS") -// setupFlags() -// assert.Equal(t, zbot.Flags.Level, false, "User Level Off") - -// os.Setenv("ZBOT_FLAG_ACTIVATE_LEVELS", "true") -// setupFlags() -// assert.Equal(t, zbot.Flags.Level, true, "User Level ON") -// } - -// func TestMain(t *testing.T) { - -// } diff --git a/server/server.go b/server/server.go new file mode 100644 index 0000000..e2b367c --- /dev/null +++ b/server/server.go @@ -0,0 +1,69 @@ +package server + +import ( + "fmt" + "net/http" + + "github.com/mitchellh/mapstructure" + log "github.com/sirupsen/logrus" + tb "gopkg.in/tucnak/telebot.v2" +) + +//Channel definition +type Channel struct { + ID int64 + Title string + AuthToken string +} + +//Start http server in a given port +func Start(serverPort int, bot *tb.Bot, c interface{}) { + log.Info(fmt.Sprintf("Starting http server at port: %d", serverPort)) + channels := []Channel{} + mapstructure.Decode(c, &channels) + + http.HandleFunc("/messages", apiMessages(bot, channels)) + // http.HandleFunc("/modules", apiModules(bot, channels)) + err := http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", serverPort), nil) + + if err != nil { + log.Fatal("ListenAndServe: " + err.Error()) + } + +} + +func apiMessages(bot *tb.Bot, channels []Channel) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + log.Debug(fmt.Sprintf("GET params: %v", r.URL.Query())) + + authToken := r.URL.Query().Get("token") + chatID := getChatID(authToken, channels) + data := r.URL.Query().Get("data") + + if authToken != "" && chatID != 0 { + + if data != "" { + var to = tb.Chat{} + to.ID = chatID + bot.Send(&to, data) + w.Write([]byte(fmt.Sprintf("OK"))) + } + + } + + w.WriteHeader(http.StatusForbidden) + w.Write([]byte(fmt.Sprintf("Forbidden"))) + } +} + +//getChatId return the chat_id associated with that token +func getChatID(token string, channels []Channel) int64 { + + for i := range channels { + if channels[i].AuthToken == token { + return channels[i].ID + } + } + + return 0 +} diff --git a/server/server_test.go b/server/server_test.go new file mode 100644 index 0000000..d463e4e --- /dev/null +++ b/server/server_test.go @@ -0,0 +1,28 @@ +package server + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetChatID(t *testing.T) { + + channels := []Channel{ + { + AuthToken: "authToken", + ID: 1234, + }, + { + AuthToken: "authToken2", + ID: 0, + }, + } + + assert.Equal(t, int64(1234), getChatID("authToken", channels), "GET ID using token") + assert.Equal(t, int64(0), getChatID("token2", channels), "GET ID using token") +} + +func TestAPI(t *testing.T) { + +} diff --git a/zbot.conf b/zbot.conf index 0eb26b5..e6365fe 100644 --- a/zbot.conf +++ b/zbot.conf @@ -5,12 +5,16 @@ zbot: level: false db: engine: sqlite - name: db_name file: path_to_sqlite_file.db - host: 127.0.0.1 - port: 3306 - username: db_username - password: db_password +webhook: + disable: true + port: 13371 + auth: + - channel: channel1 + id: 1234 + token: + - channel: channel2 + token: commands: learn: disabled: diff --git a/zbot/zbot.go b/zbot/zbot.go index 16681de..20944db 100644 --- a/zbot/zbot.go +++ b/zbot/zbot.go @@ -12,6 +12,7 @@ import ( log "github.com/sirupsen/logrus" command "github.com/ssalvatori/zbot-telegram/commands" "github.com/ssalvatori/zbot-telegram/db" + "github.com/ssalvatori/zbot-telegram/server" "github.com/ssalvatori/zbot-telegram/user" "github.com/ssalvatori/zbot-telegram/utils" tb "gopkg.in/tucnak/telebot.v2" @@ -24,8 +25,24 @@ type ExternalModulesList []struct { Description string } -// //externalModule definition of an external module -// type externalModule +//Channel definition +type Channel struct { + ID int64 + Title string + AuthToken string +} + +//ConfigurationFlags configurations false means the feature is disabled +type ConfigurationFlags struct { + Ignore bool + Level bool +} + +//ConfigurationWebhook configuration +type ConfigurationWebhook struct { + Enable bool + Port int +} var ( version = "dev-master" @@ -43,39 +60,39 @@ var ( IgnoreDuration = 300 //DisableLearnChannels List of channels were Learn modules should be disabled (use comma as separator) DisableLearnChannels = "" -) - -//ExternalModules List of extra modules -var ExternalModules ExternalModulesList -//ConfigurationFlags configurations false means the feature is disabled -type ConfigurationFlags struct { - Ignore bool - Level bool -} - -//Db interface to the database -var Db db.ZbotDatabase - -var levelsConfig = command.Levels{ - Ignore: 100, - Lock: 1000, - Learn: 0, - Append: 0, - Forget: 1000, - Who: 0, - Top: 0, - Stats: 0, - Version: 0, - Ping: 0, - Last: 0, - Rand: 0, - Find: 0, - Get: 0, - Search: 0, - External: 0, - Level: 0, -} + //Webhook configuration + Webhook = ConfigurationWebhook{Enable: false, Port: 11337} + + //Channels List of Channels where the bot is present (this list is growing with new messages) + Channels []Channel + + //ExternalModules List of extra modules + ExternalModules ExternalModulesList + + //Db interface to the database + Db db.ZbotDatabase + + levelsConfig = command.Levels{ + Ignore: 100, + Lock: 1000, + Learn: 0, + Append: 0, + Forget: 1000, + Who: 0, + Top: 0, + Stats: 0, + Version: 0, + Ping: 0, + Last: 0, + Rand: 0, + Find: 0, + Get: 0, + Search: 0, + External: 0, + Level: 0, + } +) //Execute run Zbot func Execute() { @@ -90,17 +107,7 @@ func Execute() { poller := &tb.LongPoller{Timeout: 10 * time.Second} - middleware := tb.NewMiddlewarePoller(poller, func(msg *tb.Update) bool { - if msg.Message == nil { - return true - } - - if strings.Contains(msg.Message.Text, "spam") { - return false - } - - return true - }) + middleware := tb.NewMiddlewarePoller(poller, middleware) bot, err := tb.NewBot(tb.Settings{ Token: APIToken, @@ -165,9 +172,11 @@ func Execute() { } }) - // time.AfterFunc(100*time.Second, bot.Stop) - - bot.Start() + go bot.Start() + if Webhook.Enable { + go server.Start(Webhook.Port, bot, Channels) + } + select {} // keep running } func runExternalModule(db db.ZbotDatabase, message *tb.Message, modules ExternalModulesList) string { @@ -306,3 +315,35 @@ func GetDisabledCommands() []string { func SetDisabledLearnChannels(channelsList []string) { command.DisableLearnChannels = channelsList } + +func appendChannel(channels []Channel, chat tb.Chat) []Channel { + + for i := range channels { + if channels[i].ID == chat.ID { + channels[i].Title = chat.Title + return channels + } else if channels[i].ID == 0 && chat.Title == channels[i].Title { + channels[i].ID = chat.ID + return channels + } + } + + channels = append(channels, Channel{ID: chat.ID, Title: chat.Title}) + return channels +} + +func middleware(msg *tb.Update) bool { + if msg.Message == nil { + return true + } + + if strings.Contains(msg.Message.Text, "spam") { + return false + } + + if msg.Message.Chat.Type == "group" || msg.Message.Chat.Type == "supergroup" { + Channels = appendChannel(Channels, *msg.Message.Chat) + } + + return true +} diff --git a/zbot/zbot_test.go b/zbot/zbot_test.go index a6ebd5c..bdb6d79 100644 --- a/zbot/zbot_test.go +++ b/zbot/zbot_test.go @@ -339,6 +339,42 @@ func TestProcessingNotEnoughPermissions(t *testing.T) { assert.Equal(t, "Your level is not enough < 1000", result, "Not enough permissions to use a command") } +func TestAppendChannel(t *testing.T) { + chat := &tb.Chat{ + Type: "group", + ID: -1234, + Title: "test 1", + } + + channels := []Channel{} + assert.Equal(t, []Channel{{ID: -1234, Title: "test 1"}}, appendChannel(channels, *chat), "Add Channel") + + channels = []Channel{{ID: -66, Title: "test 1"}} + assert.Equal(t, []Channel{{ID: -66, Title: "test 1"}, {ID: -1234, Title: "test 1"}}, appendChannel(channels, *chat), "Add Channel") + + channels = []Channel{{ID: -1234, Title: "test already"}} + assert.Equal(t, []Channel{{ID: -1234, Title: "test 1"}}, appendChannel(channels, *chat), "Channel already present (updating title)") + + channels = []Channel{{ID: -12345, Title: "test already"}, {ID: 0, Title: "test 1"}} + assert.Equal(t, []Channel{{ID: -12345, Title: "test already"}, {ID: -1234, Title: "test 1"}}, appendChannel(channels, *chat), "Channel's ID is copied from message") +} + +func TestMiddleware(t *testing.T) { + + msg := tb.Update{} + assert.True(t, middleware(&msg), "No Message") + + msg = tb.Update{Message: &tb.Message{Text: "test spam"}} + assert.False(t, middleware(&msg), "No Message") + + msg = tb.Update{Message: &tb.Message{Text: "test", Chat: &tb.Chat{Type: "private"}}} + assert.True(t, middleware(&msg), "Private message") + + msg = tb.Update{Message: &tb.Message{Text: "test", Chat: &tb.Chat{Type: "group"}}} + assert.True(t, middleware(&msg), "Group message") + +} + /* func TestExecute(t *testing.T) { dbMock := &db.ZbotDatabaseMock{