From bf643f103d2102a281b16492d68e135ffd66fcd8 Mon Sep 17 00:00:00 2001 From: gohumble <55599638+gohumble@users.noreply.github.com> Date: Sun, 27 Mar 2022 22:19:38 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=AA=84=20update=20telebot=20v3=20?= =?UTF-8?q?=F0=9F=A4=96=20(#325)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🚧 minor changes to all handlers... * 🚧 passing callback to tryEditStack * 🚧 edit and delete callback messages * 🚧 refactor again * 🚧 uncomment this * 🚧 using ctx.Message().Text * 🚧 refactor * 🚧 refactor * 🚧 uncomment * context not queruy * 🚧 update forked lightningtipbot * 🚧 reset ArticleResult * fix inline receive * readd shop * remove chat from shopView Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> --- go.mod | 2 +- go.sum | 23 +++ internal/lnbits/types.go | 2 +- internal/lnbits/webhook/webhook.go | 2 +- internal/lnurl/lnurl.go | 2 +- internal/rate/limiter.go | 2 +- internal/telegram/amounts.go | 27 ++-- internal/telegram/balance.go | 17 +-- internal/telegram/bot.go | 2 +- internal/telegram/buttons.go | 6 +- internal/telegram/database.go | 2 +- internal/telegram/donate.go | 15 +- internal/telegram/edit.go | 2 +- internal/telegram/faucet.go | 73 +++++----- internal/telegram/files.go | 11 +- internal/telegram/groups.go | 52 +++---- internal/telegram/handler.go | 179 ++++++++++------------- internal/telegram/help.go | 33 ++--- internal/telegram/inline_query.go | 67 +++++---- internal/telegram/inline_receive.go | 69 ++++----- internal/telegram/inline_send.go | 39 ++--- internal/telegram/intercept/callback.go | 77 ---------- internal/telegram/intercept/context.go | 84 +++++++++++ internal/telegram/intercept/message.go | 77 ---------- internal/telegram/intercept/query.go | 77 ---------- internal/telegram/interceptor.go | 184 ++++++++++-------------- internal/telegram/invoice.go | 8 +- internal/telegram/link.go | 9 +- internal/telegram/lnurl-auth.go | 15 +- internal/telegram/lnurl-pay.go | 21 +-- internal/telegram/lnurl-withdraw.go | 35 +++-- internal/telegram/lnurl.go | 19 +-- internal/telegram/message.go | 2 +- internal/telegram/pay.go | 81 +++++------ internal/telegram/photo.go | 21 +-- internal/telegram/send.go | 100 ++++++------- internal/telegram/shop.go | 145 ++++++++++++------- internal/telegram/shop_helpers.go | 39 +++-- internal/telegram/start.go | 25 ++-- internal/telegram/state.go | 5 +- internal/telegram/telegram.go | 2 +- internal/telegram/text.go | 23 +-- internal/telegram/tip.go | 10 +- internal/telegram/tipjar.go | 52 ++++--- internal/telegram/tooltip.go | 2 +- internal/telegram/tooltip_test.go | 2 +- internal/telegram/transaction.go | 2 +- internal/telegram/users.go | 2 +- main.go | 4 +- 49 files changed, 833 insertions(+), 917 deletions(-) delete mode 100644 internal/telegram/intercept/callback.go create mode 100644 internal/telegram/intercept/context.go delete mode 100644 internal/telegram/intercept/message.go delete mode 100644 internal/telegram/intercept/query.go diff --git a/go.mod b/go.mod index 84420c1..e3bc764 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/tidwall/gjson v1.10.2 golang.org/x/text v0.3.5 golang.org/x/time v0.0.0-20191024005414-555d28b269f0 - gopkg.in/lightningtipbot/telebot.v2 v2.4.2-0.20211217193303-c005cce171ac + gopkg.in/lightningtipbot/telebot.v3 v3.0.0-20220326213923-f323bb71ac8e // indirect gorm.io/driver/sqlite v1.1.4 gorm.io/gorm v1.21.12 ) diff --git a/go.sum b/go.sum index 2ae2730..fbf0193 100644 --- a/go.sum +++ b/go.sum @@ -136,6 +136,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fiatjaf/go-lnurl v1.4.0 h1:hVFEEJD2A9D6ojEcqLyD54CM2ZJ9Tzs2jNKw/GNq52A= github.com/fiatjaf/go-lnurl v1.4.0/go.mod h1:BqA8WXAOzntF7Z3EkVO7DfP4y5rhWUmJ/Bu9KBke+rs= github.com/fiatjaf/go-lnurl v1.8.3 h1:ONQUQsXIZKkzrzax2SMUr5W0PreluhO4tct1JM0V/MA= @@ -170,10 +172,15 @@ github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1 github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-redis/redis/v8 v8.8.2 h1:O/NcHqobw7SEptA0yA6up6spZVFtwE06SXM8rgLtsP8= github.com/go-redis/redis/v8 v8.8.2/go.mod h1:F7resOH5Kdug49Otu24RjHWwgK7u9AmtqWMnCV1iP5Y= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -306,6 +313,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= github.com/lightninglabs/neutrino v0.11.0/go.mod h1:CuhF0iuzg9Sp2HO6ZgXgayviFTn1QHdSTJlMncK80wg= @@ -331,8 +339,13 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN github.com/makiuchi-d/gozxing v0.0.2 h1:TGSCQRXd9QL1ze1G1JE9sZBMEr6/HLx7m5ADlLUgq7E= github.com/makiuchi-d/gozxing v0.0.2/go.mod h1:Tt5nF+kNliU+5MDxqPpsFrtsWNdABQho/xdCZZVKCQc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ= @@ -641,6 +654,7 @@ golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -649,6 +663,10 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= @@ -738,12 +756,16 @@ gopkg.in/lightningtipbot/telebot.v2 v2.4.2-0.20211207185736-224e4f70c5ad h1:HR3v gopkg.in/lightningtipbot/telebot.v2 v2.4.2-0.20211207185736-224e4f70c5ad/go.mod h1:lUH49SRidDcQGyXPIL9tR2cN3vztcLBo47AqFUgHgIA= gopkg.in/lightningtipbot/telebot.v2 v2.4.2-0.20211217193303-c005cce171ac h1:EcXyrTUaQJYiHtLQstXdW04sRH9HwH9mpaxy9Lkcomc= gopkg.in/lightningtipbot/telebot.v2 v2.4.2-0.20211217193303-c005cce171ac/go.mod h1:lUH49SRidDcQGyXPIL9tR2cN3vztcLBo47AqFUgHgIA= +gopkg.in/lightningtipbot/telebot.v3 v3.0.0-20220326213923-f323bb71ac8e h1:x58PfjVq6dbYSzM4URM9QfKDKVru1CpngxCM5pGqwbk= +gopkg.in/lightningtipbot/telebot.v3 v3.0.0-20220326213923-f323bb71ac8e/go.mod h1:kIC/Dlp2OjWhVrOkZDN4iEoCaqoac5w1UjpKY6Ftf+U= gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA= gopkg.in/macaroon.v2 v2.0.0/go.mod h1:+I6LnTMkm/uV5ew/0nsulNjL16SK4+C8yDmRUzHR17I= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/telebot.v3 v3.0.0 h1:UgHIiE/RdjoDi6nf4xACM7PU3TqiPVV9vvTydCEnrTo= +gopkg.in/telebot.v3 v3.0.0/go.mod h1:7rExV8/0mDDNu9epSrDm/8j22KLaActH1Tbee6YjzWg= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= @@ -761,6 +783,7 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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-20210107192922-496545a6307b/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= diff --git a/internal/lnbits/types.go b/internal/lnbits/types.go index a50ba8e..7895952 100644 --- a/internal/lnbits/types.go +++ b/internal/lnbits/types.go @@ -9,7 +9,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/imroc/req" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) type Client struct { diff --git a/internal/lnbits/webhook/webhook.go b/internal/lnbits/webhook/webhook.go index 473186e..b17e2b9 100644 --- a/internal/lnbits/webhook/webhook.go +++ b/internal/lnbits/webhook/webhook.go @@ -17,7 +17,7 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/storage" "github.com/gorilla/mux" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" "github.com/LightningTipBot/LightningTipBot/internal/i18n" ) diff --git a/internal/lnurl/lnurl.go b/internal/lnurl/lnurl.go index 2856032..a92e8aa 100644 --- a/internal/lnurl/lnurl.go +++ b/internal/lnurl/lnurl.go @@ -12,7 +12,7 @@ import ( "time" "github.com/eko/gocache/store" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" "github.com/LightningTipBot/LightningTipBot/internal" "github.com/LightningTipBot/LightningTipBot/internal/api" diff --git a/internal/rate/limiter.go b/internal/rate/limiter.go index 74f5ff0..6851a1d 100644 --- a/internal/rate/limiter.go +++ b/internal/rate/limiter.go @@ -7,7 +7,7 @@ import ( "sync" "golang.org/x/time/rate" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) // Limiter diff --git a/internal/telegram/amounts.go b/internal/telegram/amounts.go index 135229d..7241a39 100644 --- a/internal/telegram/amounts.go +++ b/internal/telegram/amounts.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "strconv" "strings" @@ -16,7 +17,7 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/price" "github.com/LightningTipBot/LightningTipBot/internal/runtime" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) func getArgumentFromCommand(input string, which int) (output string, err error) { @@ -120,7 +121,7 @@ func (bot *TipBot) askForAmount(ctx context.Context, id string, eventType string // enterAmountHandler is invoked in anyTextHandler when the user needs to enter an amount // the amount is then stored as an entry in the user's stateKey in the user database // any other handler that relies on this, needs to load the resulting amount from the database -func (bot *TipBot) enterAmountHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) enterAmountHandler(ctx intercept.Context) (intercept.Context, error) { user := LoadUser(ctx) if user.Wallet == nil { return ctx, errors.Create(errors.UserNoWalletError) @@ -139,10 +140,10 @@ func (bot *TipBot) enterAmountHandler(ctx context.Context, m *tb.Message) (conte return ctx, err } - amount, err := getAmount(m.Text) + amount, err := getAmount(ctx.Message().Text) if err != nil { log.Warnf("[enterAmountHandler] %s", err.Error()) - bot.trySendMessage(m.Sender, Translate(ctx, "lnurlInvalidAmountMessage")) + bot.trySendMessage(ctx.Message().Sender, Translate(ctx, "lnurlInvalidAmountMessage")) ResetUserState(user, bot) return ctx, err } @@ -151,7 +152,7 @@ func (bot *TipBot) enterAmountHandler(ctx context.Context, m *tb.Message) (conte (amount > int64(EnterAmountStateData.AmountMax/1000) || amount < int64(EnterAmountStateData.AmountMin/1000)) { // this line then checks whether the amount is in the range err = fmt.Errorf("amount not in range") log.Warnf("[enterAmountHandler] %s", err.Error()) - bot.trySendMessage(m.Sender, fmt.Sprintf(Translate(ctx, "lnurlInvalidAmountRangeMessage"), EnterAmountStateData.AmountMin/1000, EnterAmountStateData.AmountMax/1000)) + bot.trySendMessage(ctx.Sender(), fmt.Sprintf(Translate(ctx, "lnurlInvalidAmountRangeMessage"), EnterAmountStateData.AmountMin/1000, EnterAmountStateData.AmountMax/1000)) ResetUserState(user, bot) return ctx, errors.Create(errors.InvalidSyntaxError) } @@ -179,7 +180,7 @@ func (bot *TipBot) enterAmountHandler(ctx context.Context, m *tb.Message) (conte return ctx, err } SetUserState(user, bot, lnbits.UserHasEnteredAmount, string(StateDataJson)) - return bot.lnurlPayHandlerSend(ctx, m) + return bot.lnurlPayHandlerSend(ctx) case "LnurlWithdrawState": tx := &LnurlWithdrawState{Base: storage.New(storage.ID(EnterAmountStateData.ID))} mutex.LockWithContext(ctx, tx.ID) @@ -200,21 +201,21 @@ func (bot *TipBot) enterAmountHandler(ctx context.Context, m *tb.Message) (conte return ctx, err } SetUserState(user, bot, lnbits.UserHasEnteredAmount, string(StateDataJson)) - return bot.lnurlWithdrawHandlerWithdraw(ctx, m) + return bot.lnurlWithdrawHandlerWithdraw(ctx) case "CreateInvoiceState": - m.Text = fmt.Sprintf("/invoice %d", amount) + ctx.Message().Text = fmt.Sprintf("/invoice %d", amount) SetUserState(user, bot, lnbits.UserHasEnteredAmount, "") - return bot.invoiceHandler(ctx, m) + return bot.invoiceHandler(ctx) case "CreateDonationState": - m.Text = fmt.Sprintf("/donate %d", amount) + ctx.Message().Text = fmt.Sprintf("/donate %d", amount) SetUserState(user, bot, lnbits.UserHasEnteredAmount, "") - return bot.donationHandler(ctx, m) + return bot.donationHandler(ctx) case "CreateSendState": splits := strings.SplitAfterN(EnterAmountStateData.OiringalCommand, " ", 2) if len(splits) > 1 { - m.Text = fmt.Sprintf("/send %d %s", amount, splits[1]) + ctx.Message().Text = fmt.Sprintf("/send %d %s", amount, splits[1]) SetUserState(user, bot, lnbits.UserHasEnteredAmount, "") - return bot.sendHandler(ctx, m) + return bot.sendHandler(ctx) } return ctx, errors.Create(errors.InvalidSyntaxError) default: diff --git a/internal/telegram/balance.go b/internal/telegram/balance.go index def024d..1e898c4 100644 --- a/internal/telegram/balance.go +++ b/internal/telegram/balance.go @@ -1,19 +1,20 @@ package telegram import ( - "context" "fmt" "github.com/LightningTipBot/LightningTipBot/internal/errors" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) -func (bot *TipBot) balanceHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) balanceHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() // check and print all commands if len(m.Text) > 0 { - bot.anyTextHandler(ctx, m) + bot.anyTextHandler(ctx) } // reply only in private message @@ -28,18 +29,18 @@ func (bot *TipBot) balanceHandler(ctx context.Context, m *tb.Message) (context.C } if !user.Initialized { - return bot.startHandler(ctx, m) + return bot.startHandler(ctx) } - usrStr := GetUserStr(m.Sender) + usrStr := GetUserStr(ctx.Sender()) balance, err := bot.GetUserBalance(user) if err != nil { log.Errorf("[/balance] Error fetching %s's balance: %s", usrStr, err) - bot.trySendMessage(m.Sender, Translate(ctx, "balanceErrorMessage")) + bot.trySendMessage(ctx.Sender(), Translate(ctx, "balanceErrorMessage")) return ctx, err } log.Infof("[/balance] %s's balance: %d sat\n", usrStr, balance) - bot.trySendMessage(m.Sender, fmt.Sprintf(Translate(ctx, "balanceMessage"), balance)) + bot.trySendMessage(ctx.Sender(), fmt.Sprintf(Translate(ctx, "balanceMessage"), balance)) return ctx, nil } diff --git a/internal/telegram/bot.go b/internal/telegram/bot.go index 4eb2b1f..e324d61 100644 --- a/internal/telegram/bot.go +++ b/internal/telegram/bot.go @@ -19,7 +19,7 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/storage" gocache "github.com/patrickmn/go-cache" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" "gorm.io/gorm" ) diff --git a/internal/telegram/buttons.go b/internal/telegram/buttons.go index 57982ee..c842d3e 100644 --- a/internal/telegram/buttons.go +++ b/internal/telegram/buttons.go @@ -6,7 +6,7 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/lnbits" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) // we can't use space in the label of buttons, because string splitting will mess everything up. @@ -19,13 +19,13 @@ const ( ) var ( - mainMenu = &tb.ReplyMarkup{ResizeReplyKeyboard: true} + mainMenu = &tb.ReplyMarkup{ResizeKeyboard: true} btnHelpMainMenu = mainMenu.Text(MainMenuCommandHelp) btnSendMainMenu = mainMenu.Text(MainMenuCommandSend) btnBalanceMainMenu = mainMenu.Text(MainMenuCommandBalance) btnInvoiceMainMenu = mainMenu.Text(MainMenuCommandInvoice) - sendToMenu = &tb.ReplyMarkup{ResizeReplyKeyboard: true} + sendToMenu = &tb.ReplyMarkup{ResizeKeyboard: true} sendToButtons = []tb.Btn{} btnSendMenuEnter = mainMenu.Text(SendMenuCommandEnter) ) diff --git a/internal/telegram/database.go b/internal/telegram/database.go index 6c0ce36..4d78619 100644 --- a/internal/telegram/database.go +++ b/internal/telegram/database.go @@ -23,7 +23,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/LightningTipBot/LightningTipBot/internal/lnbits" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" "gorm.io/driver/sqlite" "gorm.io/gorm" ) diff --git a/internal/telegram/donate.go b/internal/telegram/donate.go index b4eb93b..787a318 100644 --- a/internal/telegram/donate.go +++ b/internal/telegram/donate.go @@ -3,6 +3,7 @@ package telegram import ( "context" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "io" "io/ioutil" "net/http" @@ -14,7 +15,7 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/lnbits" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) // PLEASE DO NOT CHANGE THE CODE IN THIS FILE @@ -34,9 +35,10 @@ func helpDonateUsage(ctx context.Context, errormsg string) string { } } -func (bot TipBot) donationHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot TipBot) donationHandler(ctx intercept.Context) (intercept.Context, error) { // check and print all commands - bot.anyTextHandler(ctx, m) + m := ctx.Message() + bot.anyTextHandler(ctx) user := LoadUser(ctx) if user.Wallet == nil { return ctx, errors.Create(errors.UserNoWalletError) @@ -118,7 +120,8 @@ func (rot13 rot13Reader) Read(b []byte) (int, error) { return n, err } -func (bot TipBot) parseCmdDonHandler(ctx context.Context, m *tb.Message) error { +func (bot TipBot) parseCmdDonHandler(ctx intercept.Context) error { + m := ctx.Message() arg := "" if strings.HasPrefix(strings.ToLower(m.Text), "/send") { arg, _ = getArgumentFromCommand(m.Text, 2) @@ -150,7 +153,7 @@ func (bot TipBot) parseCmdDonHandler(ctx context.Context, m *tb.Message) error { bot.trySendMessage(m.Sender, str.MarkdownEscape(donationInterceptMessage)) m.Text = fmt.Sprintf("/donate %d", amount) - bot.donationHandler(ctx, m) - // returning nil here will abort the parent handler (/pay or /tip) + bot.donationHandler(ctx) + // returning nil here will abort the parent ctx (/pay or /tip) return nil } diff --git a/internal/telegram/edit.go b/internal/telegram/edit.go index 6aa0cb4..1c8ac0e 100644 --- a/internal/telegram/edit.go +++ b/internal/telegram/edit.go @@ -6,7 +6,7 @@ import ( cmap "github.com/orcaman/concurrent-map" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) var editStack cmap.ConcurrentMap diff --git a/internal/telegram/faucet.go b/internal/telegram/faucet.go index ff396d0..8610313 100644 --- a/internal/telegram/faucet.go +++ b/internal/telegram/faucet.go @@ -7,6 +7,8 @@ import ( "strings" "time" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" + "github.com/LightningTipBot/LightningTipBot/internal/runtime/mutex" "github.com/LightningTipBot/LightningTipBot/internal/runtime/once" "github.com/LightningTipBot/LightningTipBot/internal/storage" @@ -19,11 +21,11 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/lnbits" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) var ( - inlineFaucetMenu = &tb.ReplyMarkup{ResizeReplyKeyboard: true} + inlineFaucetMenu = &tb.ReplyMarkup{ResizeKeyboard: true} btnCancelInlineFaucet = inlineFaucetMenu.Data("đŸšĢ Cancel", "cancel_faucet_inline") btnAcceptInlineFaucet = inlineFaucetMenu.Data("✅ Collect", "confirm_faucet_inline") ) @@ -136,28 +138,28 @@ func (bot TipBot) makeFaucet(ctx context.Context, m *tb.Message, query bool) (*I return faucet, err } -func (bot TipBot) makeQueryFaucet(ctx context.Context, q *tb.Query, query bool) (*InlineFaucet, error) { - faucet, err := bot.createFaucet(ctx, q.Text, &q.From) +func (bot TipBot) makeQueryFaucet(ctx intercept.Context) (*InlineFaucet, error) { + faucet, err := bot.createFaucet(ctx, ctx.Query().Text, ctx.Query().Sender) if err != nil { switch err.(errors.TipBotError).Code { case errors.DecodeAmountError: - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineQueryFaucetTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineQueryFaucetTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) return nil, err case errors.DecodePerUserAmountError: - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineQueryFaucetTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineQueryFaucetTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) return nil, err case errors.InvalidAmountError: - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineSendInvalidAmountMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineSendInvalidAmountMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) return nil, err case errors.InvalidAmountPerUserError: - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineFaucetInvalidPeruserAmountMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineFaucetInvalidPeruserAmountMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) return nil, err case errors.GetBalanceError: - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineQueryFaucetTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineQueryFaucetTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) return nil, err case errors.BalanceToLowError: log.Errorf(err.Error()) - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineSendBalanceLowMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineSendBalanceLowMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryFaucetDescription"), bot.Telegram.Me.Username)) return nil, err } } @@ -165,7 +167,7 @@ func (bot TipBot) makeQueryFaucet(ctx context.Context, q *tb.Query, query bool) } func (bot TipBot) makeFaucetKeyboard(ctx context.Context, id string) *tb.ReplyMarkup { - inlineFaucetMenu := &tb.ReplyMarkup{ResizeReplyKeyboard: true} + inlineFaucetMenu := &tb.ReplyMarkup{ResizeKeyboard: true} acceptInlineFaucetButton := inlineFaucetMenu.Data(Translate(ctx, "collectButtonMessage"), "confirm_faucet_inline", id) cancelInlineFaucetButton := inlineFaucetMenu.Data(Translate(ctx, "cancelButtonMessage"), "cancel_faucet_inline", id) inlineFaucetMenu.Inline( @@ -176,20 +178,20 @@ func (bot TipBot) makeFaucetKeyboard(ctx context.Context, id string) *tb.ReplyMa return inlineFaucetMenu } -func (bot TipBot) faucetHandler(ctx context.Context, m *tb.Message) (context.Context, error) { - bot.anyTextHandler(ctx, m) - if m.Private() { - bot.trySendMessage(m.Sender, fmt.Sprintf(Translate(ctx, "inlineFaucetHelpText"), Translate(ctx, "inlineFaucetHelpFaucetInGroup"))) +func (bot TipBot) faucetHandler(ctx intercept.Context) (intercept.Context, error) { + bot.anyTextHandler(ctx) + if ctx.Message().Private() { + bot.trySendMessage(ctx.Message().Sender, fmt.Sprintf(Translate(ctx, "inlineFaucetHelpText"), Translate(ctx, "inlineFaucetHelpFaucetInGroup"))) return ctx, errors.Create(errors.NoPrivateChatError) } - ctx = bot.mapFaucetLanguage(ctx, m.Text) - inlineFaucet, err := bot.makeFaucet(ctx, m, false) + ctx.Context = bot.mapFaucetLanguage(ctx, ctx.Text()) + inlineFaucet, err := bot.makeFaucet(ctx, ctx.Message(), false) if err != nil { log.Warnf("[faucet] %s", err.Error()) return ctx, err } - fromUserStr := GetUserStr(m.Sender) - mFaucet := bot.trySendMessage(m.Chat, inlineFaucet.Message, bot.makeFaucetKeyboard(ctx, inlineFaucet.ID)) + fromUserStr := GetUserStr(ctx.Message().Sender) + mFaucet := bot.trySendMessage(ctx.Message().Chat, inlineFaucet.Message, bot.makeFaucetKeyboard(ctx, inlineFaucet.ID)) log.Infof("[faucet] %s created faucet %s: %d sat (%d per user)", fromUserStr, inlineFaucet.ID, inlineFaucet.Amount, inlineFaucet.PerUserAmount) // log faucet link if possible @@ -199,8 +201,8 @@ func (bot TipBot) faucetHandler(ctx context.Context, m *tb.Message) (context.Con return ctx, inlineFaucet.Set(inlineFaucet, bot.Bunt) } -func (bot TipBot) handleInlineFaucetQuery(ctx context.Context, q *tb.Query) (context.Context, error) { - inlineFaucet, err := bot.makeQueryFaucet(ctx, q, false) +func (bot TipBot) handleInlineFaucetQuery(ctx intercept.Context) (intercept.Context, error) { + inlineFaucet, err := bot.makeQueryFaucet(ctx) if err != nil { log.Errorf("[handleInlineFaucetQuery] %s", err.Error()) return ctx, err @@ -218,7 +220,7 @@ func (bot TipBot) handleInlineFaucetQuery(ctx context.Context, q *tb.Query) (con // required for photos ThumbURL: url, } - result.ReplyMarkup = &tb.InlineKeyboardMarkup{InlineKeyboard: bot.makeFaucetKeyboard(ctx, inlineFaucet.ID).InlineKeyboard} + result.ReplyMarkup = &tb.ReplyMarkup{InlineKeyboard: bot.makeFaucetKeyboard(ctx, inlineFaucet.ID).InlineKeyboard} results[i] = result // needed to set a unique string ID for each result results[i].SetResultID(inlineFaucet.ID) @@ -227,7 +229,7 @@ func (bot TipBot) handleInlineFaucetQuery(ctx context.Context, q *tb.Query) (con log.Infof("[faucet] %s:%d created inline faucet %s: %d sat (%d per user)", GetUserStr(inlineFaucet.From.Telegram), inlineFaucet.From.Telegram.ID, inlineFaucet.ID, inlineFaucet.Amount, inlineFaucet.PerUserAmount) } - err = bot.Telegram.Answer(q, &tb.QueryResponse{ + err = bot.Telegram.Answer(ctx.Query(), &tb.QueryResponse{ Results: results, CacheTime: 1, }) @@ -238,7 +240,8 @@ func (bot TipBot) handleInlineFaucetQuery(ctx context.Context, q *tb.Query) (con return ctx, nil } -func (bot *TipBot) acceptInlineFaucetHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) acceptInlineFaucetHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() to := LoadUser(ctx) tx := &InlineFaucet{Base: storage.New(storage.ID(c.Data))} mutex.LockWithContext(ctx, tx.ID) @@ -265,7 +268,7 @@ func (bot *TipBot) acceptInlineFaucetHandler(ctx context.Context, c *tb.Callback if from.Telegram.ID == to.Telegram.ID { log.Debugf("[faucet] %s is the owner faucet %s", GetUserStr(to.Telegram), inlineFaucet.ID) - ctx = context.WithValue(ctx, "callback_response", Translate(ctx, "sendYourselfMessage")) + ctx.Context = context.WithValue(ctx, "callback_response", Translate(ctx, "sendYourselfMessage")) return ctx, errors.Create(errors.SelfPaymentError) } // check if to user has already taken from the faucet @@ -273,7 +276,7 @@ func (bot *TipBot) acceptInlineFaucetHandler(ctx context.Context, c *tb.Callback if a.Telegram.ID == to.Telegram.ID { // to user is already in To slice, has taken from facuet log.Debugf("[faucet] %s:%d already took from faucet %s", GetUserStr(to.Telegram), to.Telegram.ID, inlineFaucet.ID) - ctx = context.WithValue(ctx, "callback_response", Translate(ctx, "inlineFaucetAlreadyTookMessage")) + ctx.Context = context.WithValue(ctx, "callback_response", Translate(ctx, "inlineFaucetAlreadyTookMessage")) return ctx, errors.Create(errors.UnknownError) } } @@ -310,7 +313,7 @@ func (bot *TipBot) acceptInlineFaucetHandler(ctx context.Context, c *tb.Callback // bot.trySendMessage(from.Telegram, Translate(ctx, "sendErrorMessage")) errMsg := fmt.Sprintf("[faucet] Transaction failed: %s", err.Error()) log.Warnln(errMsg) - ctx = context.WithValue(ctx, "callback_response", Translate(ctx, "errorTryLaterMessage")) + ctx.Context = context.WithValue(ctx, "callback_response", Translate(ctx, "errorTryLaterMessage")) // if faucet fails, cancel it: // c.Sender.ID = inlineFaucet.From.Telegram.ID // overwrite the sender of the callback to be the faucet owner // log.Debugf("[faucet] Canceling faucet %s...", inlineFaucet.ID) @@ -325,7 +328,7 @@ func (bot *TipBot) acceptInlineFaucetHandler(ctx context.Context, c *tb.Callback inlineFaucet.RemainingAmount = inlineFaucet.RemainingAmount - inlineFaucet.PerUserAmount go func() { to_message := fmt.Sprintf(i18n.Translate(to.Telegram.LanguageCode, "inlineFaucetReceivedMessage"), fromUserStrMd, inlineFaucet.PerUserAmount) - ctx = context.WithValue(ctx, "callback_response", to_message) + ctx.Context = context.WithValue(ctx, "callback_response", to_message) bot.trySendMessage(to.Telegram, to_message) bot.trySendMessage(from.Telegram, fmt.Sprintf(i18n.Translate(from.Telegram.LanguageCode, "inlineFaucetSentMessage"), inlineFaucet.PerUserAmount, toUserStrMd)) }() @@ -344,9 +347,8 @@ func (bot *TipBot) acceptInlineFaucetHandler(ctx context.Context, c *tb.Callback // update the message if the faucet still has some sats left after this tx if inlineFaucet.RemainingAmount >= inlineFaucet.PerUserAmount { - bot.tryEditStack(c.Message, inlineFaucet.ID, inlineFaucet.Message, bot.makeFaucetKeyboard(ctx, inlineFaucet.ID)) + bot.tryEditStack(c, inlineFaucet.ID, inlineFaucet.Message, bot.makeFaucetKeyboard(ctx, inlineFaucet.ID)) } - } if inlineFaucet.RemainingAmount < inlineFaucet.PerUserAmount { log.Debugf(fmt.Sprintf("[faucet] faucet %s empty. Remaining: %d sat", inlineFaucet.ID, inlineFaucet.RemainingAmount)) @@ -369,7 +371,7 @@ func (bot *TipBot) cancelInlineFaucet(ctx context.Context, c *tb.Callback, ignor inlineFaucet := fn.(*InlineFaucet) if ignoreID || c.Sender.ID == inlineFaucet.From.Telegram.ID { faucet_cancelled_message := i18n.Translate(inlineFaucet.LanguageCode, "inlineFaucetCancelledMessage") - bot.tryEditStack(c.Message, inlineFaucet.ID, faucet_cancelled_message, &tb.ReplyMarkup{}) + bot.tryEditStack(c, inlineFaucet.ID, faucet_cancelled_message, &tb.ReplyMarkup{}) ctx = context.WithValue(ctx, "callback_response", faucet_cancelled_message) // set the inlineFaucet inactive inlineFaucet.Active = false @@ -389,7 +391,7 @@ func (bot *TipBot) finishFaucet(ctx context.Context, c *tb.Callback, inlineFauce if inlineFaucet.UserNeedsWallet { inlineFaucet.Message += "\n\n" + fmt.Sprintf(i18n.Translate(inlineFaucet.LanguageCode, "inlineFaucetCreateWalletMessage"), GetUserStrMd(bot.Telegram.Me)) } - bot.tryEditStack(c.Message, inlineFaucet.ID, inlineFaucet.Message, &tb.ReplyMarkup{}) + bot.tryEditStack(c, inlineFaucet.ID, inlineFaucet.Message, &tb.ReplyMarkup{}) log.Debugf("[faucet] Faucet finished %s", inlineFaucet.ID) once.Remove(inlineFaucet.ID) @@ -411,6 +413,9 @@ func listFaucetTakers(inlineFaucet *InlineFaucet) string { return to_str } -func (bot *TipBot) cancelInlineFaucetHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { - return bot.cancelInlineFaucet(ctx, c, false) +func (bot *TipBot) cancelInlineFaucetHandler(ctx intercept.Context) (intercept.Context, error) { + var err error + ctx.Context, err = bot.cancelInlineFaucet(ctx, ctx.Callback(), false) + return ctx, err + } diff --git a/internal/telegram/files.go b/internal/telegram/files.go index 9fa6a06..852fe8d 100644 --- a/internal/telegram/files.go +++ b/internal/telegram/files.go @@ -1,19 +1,20 @@ package telegram import ( - "context" "github.com/LightningTipBot/LightningTipBot/internal/errors" "github.com/LightningTipBot/LightningTipBot/internal/runtime" - tb "gopkg.in/lightningtipbot/telebot.v2" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" + tb "gopkg.in/lightningtipbot/telebot.v3" ) -func (bot *TipBot) fileHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) fileHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() if m.Chat.Type != tb.ChatPrivate { return ctx, errors.Create(errors.NoPrivateChatError) } user := LoadUser(ctx) if c := stateCallbackMessage[user.StateKey]; c != nil { - // found handler for this state + // found ctx for this state // now looking for user state reset ticker ticker := runtime.GetTicker(user.ID) if !ticker.Started { @@ -27,7 +28,7 @@ func (bot *TipBot) fileHandler(ctx context.Context, m *tb.Message) (context.Cont ticker.ResetChan <- struct{}{} } - return c(ctx, m) + return c(ctx) } return ctx, errors.Create(errors.NoFileFoundError) } diff --git a/internal/telegram/groups.go b/internal/telegram/groups.go index 5a86894..76105a3 100644 --- a/internal/telegram/groups.go +++ b/internal/telegram/groups.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "strings" "github.com/LightningTipBot/LightningTipBot/internal" @@ -17,7 +18,7 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/str" log "github.com/sirupsen/logrus" "github.com/skip2/go-qrcode" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) type Ticket struct { @@ -77,7 +78,7 @@ func (ticketEvent TicketEvent) Key() string { } var ( - ticketPayConfirmationMenu = &tb.ReplyMarkup{ResizeReplyKeyboard: true} + ticketPayConfirmationMenu = &tb.ReplyMarkup{ResizeKeyboard: true} btnPayTicket = paymentConfirmationMenu.Data("✅ Pay", "pay_ticket") ) @@ -95,16 +96,17 @@ var ( groupReceiveTicketInvoice = "🎟 You received *%d sat* for a ticket for group `%s` paid by user %s." ) -func (bot TipBot) groupHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot TipBot) groupHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() splits := strings.Split(m.Text, " ") if len(splits) == 1 { return ctx, nil } else if len(splits) > 1 { if splits[1] == "join" { - return bot.groupRequestJoinHandler(ctx, m) + return bot.groupRequestJoinHandler(ctx) } if splits[1] == "add" { - return bot.addGroupHandler(ctx, m) + return bot.addGroupHandler(ctx) } if splits[1] == "remove" { // todo -- implement this @@ -115,13 +117,13 @@ func (bot TipBot) groupHandler(ctx context.Context, m *tb.Message) (context.Cont } // groupRequestJoinHandler sends a payment request to the user who wants to join a group -func (bot TipBot) groupRequestJoinHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot TipBot) groupRequestJoinHandler(ctx intercept.Context) (intercept.Context, error) { user := LoadUser(ctx) // // reply only in private message - if m.Chat.Type != tb.ChatPrivate { + if ctx.Chat().Type != tb.ChatPrivate { return ctx, fmt.Errorf("not private chat") } - splits := strings.Split(m.Text, " ") + splits := strings.Split(ctx.Message().Text, " ") // if the command was /group join splitIdx := 1 // we also have the simpler command /join that can be used @@ -129,8 +131,8 @@ func (bot TipBot) groupRequestJoinHandler(ctx context.Context, m *tb.Message) (c if splits[0] == "/join" { splitIdx = 0 } - if len(splits) != splitIdx+2 || len(m.Text) > 100 { - bot.trySendMessage(m.Chat, grouJoinGroupHelpMessage) + if len(splits) != splitIdx+2 || len(ctx.Message().Text) > 100 { + bot.trySendMessage(ctx.Message().Chat, grouJoinGroupHelpMessage) return ctx, nil } groupName := strings.ToLower(splits[splitIdx+1]) @@ -138,7 +140,7 @@ func (bot TipBot) groupRequestJoinHandler(ctx context.Context, m *tb.Message) (c group := &Group{} tx := bot.GroupsDb.Where("name = ? COLLATE NOCASE", groupName).First(group) if tx.Error != nil { - bot.trySendMessage(m.Chat, groupNotFoundMessage) + bot.trySendMessage(ctx.Message().Chat, groupNotFoundMessage) return ctx, fmt.Errorf("group not found") } @@ -185,11 +187,11 @@ func (bot TipBot) groupRequestJoinHandler(ctx context.Context, m *tb.Message) (c if err != nil { errmsg := fmt.Sprintf("[/group] Error: Could not get user balance: %s", err.Error()) log.Errorln(errmsg) - bot.trySendMessage(m.Sender, Translate(ctx, "errorTryLaterMessage")) + bot.trySendMessage(ctx.Message().Sender, Translate(ctx, "errorTryLaterMessage")) return ctx, errors.New(errors.GetBalanceError, err) } if balance >= group.Ticket.Price { - return bot.groupSendPayButtonHandler(ctx, m, *ticketEvent) + return bot.groupSendPayButtonHandler(ctx, *ticketEvent) } // otherwise we send a payment request @@ -202,12 +204,12 @@ func (bot TipBot) groupRequestJoinHandler(ctx context.Context, m *tb.Message) (c log.Errorln(errmsg) return ctx, err } - ticketEvent.Message = bot.trySendMessage(m.Sender, &tb.Photo{File: tb.File{FileReader: bytes.NewReader(qr)}, Caption: fmt.Sprintf("`%s`", invoiceEvent.PaymentRequest)}) - bot.trySendMessage(m.Sender, fmt.Sprintf(groupPayInvoiceMessage, groupName)) + ticketEvent.Message = bot.trySendMessage(ctx.Message().Sender, &tb.Photo{File: tb.File{FileReader: bytes.NewReader(qr)}, Caption: fmt.Sprintf("`%s`", invoiceEvent.PaymentRequest)}) + bot.trySendMessage(ctx.Message().Sender, fmt.Sprintf(groupPayInvoiceMessage, groupName)) return ctx, nil } -func (bot *TipBot) groupSendPayButtonHandler(ctx context.Context, m *tb.Message, ticket TicketEvent) (context.Context, error) { +func (bot *TipBot) groupSendPayButtonHandler(ctx intercept.Context, ticket TicketEvent) (intercept.Context, error) { // object that holds all information about the send payment // // // create inline buttons btnPayTicket := ticketPayConfirmationMenu.Data(Translate(ctx, "payButtonMessage"), "pay_ticket", ticket.Base.ID) @@ -219,11 +221,12 @@ func (bot *TipBot) groupSendPayButtonHandler(ctx context.Context, m *tb.Message, if len(ticket.Group.Ticket.Memo) > 0 { confirmText = confirmText + fmt.Sprintf(Translate(ctx, "confirmPayAppendMemo"), str.MarkdownEscape(ticket.Group.Ticket.Memo)) } - bot.trySendMessageEditable(m.Chat, confirmText, ticketPayConfirmationMenu) + bot.trySendMessageEditable(ctx.Message().Chat, confirmText, ticketPayConfirmationMenu) return ctx, nil } -func (bot *TipBot) groupConfirmPayButtonHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) groupConfirmPayButtonHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() tx := &TicketEvent{Base: storage.New(storage.ID(c.Data))} mutex.LockWithContext(ctx, tx.ID) defer mutex.UnlockWithContext(ctx, tx.ID) @@ -241,15 +244,15 @@ func (bot *TipBot) groupConfirmPayButtonHandler(ctx context.Context, c *tb.Callb } if !ticketEvent.Active { log.Errorf("[confirmPayHandler] send not active anymore") - bot.tryEditMessage(c.Message, i18n.Translate(ticketEvent.LanguageCode, "errorTryLaterMessage"), &tb.ReplyMarkup{}) - bot.tryDeleteMessage(c.Message) + bot.tryEditMessage(c, i18n.Translate(ticketEvent.LanguageCode, "errorTryLaterMessage"), &tb.ReplyMarkup{}) + bot.tryDeleteMessage(c) return ctx, errors.Create(errors.NotActiveError) } defer ticketEvent.Set(ticketEvent, bot.Bunt) user := LoadUser(ctx) if user.Wallet == nil { - bot.tryDeleteMessage(c.Message) + bot.tryDeleteMessage(c) return ctx, errors.Create(errors.UserNoWalletError) } @@ -259,13 +262,13 @@ func (bot *TipBot) groupConfirmPayButtonHandler(ctx context.Context, c *tb.Callb if err != nil { errmsg := fmt.Sprintf("[/pay] Could not pay invoice of %s: %s", GetUserStr(user.Telegram), err) err = fmt.Errorf(i18n.Translate(ticketEvent.LanguageCode, "invoiceUndefinedErrorMessage")) - bot.tryEditMessage(c.Message, fmt.Sprintf(i18n.Translate(ticketEvent.LanguageCode, "invoicePaymentFailedMessage"), err.Error()), &tb.ReplyMarkup{}) + bot.tryEditMessage(c, fmt.Sprintf(i18n.Translate(ticketEvent.LanguageCode, "invoicePaymentFailedMessage"), err.Error()), &tb.ReplyMarkup{}) log.Errorln(errmsg) return ctx, err } // update the message and remove the button - bot.tryEditMessage(c.Message, i18n.Translate(ticketEvent.LanguageCode, "invoicePaidMessage"), &tb.ReplyMarkup{}) + bot.tryEditMessage(c, i18n.Translate(ticketEvent.LanguageCode, "invoicePaidMessage"), &tb.ReplyMarkup{}) return ctx, nil } @@ -364,7 +367,8 @@ func (bot *TipBot) groupGetInviteLinkHandler(event Event) { return } -func (bot TipBot) addGroupHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot TipBot) addGroupHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() if m.Chat.Type == tb.ChatPrivate { return ctx, fmt.Errorf("not in group") } diff --git a/internal/telegram/handler.go b/internal/telegram/handler.go index 813bc0a..d2b26eb 100644 --- a/internal/telegram/handler.go +++ b/internal/telegram/handler.go @@ -1,18 +1,17 @@ package telegram import ( - "context" "fmt" "strings" "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) -type Handler struct { +type InterceptionWrapper struct { Endpoints []interface{} - Handler interface{} + Handler intercept.Func Interceptor *Interceptor } @@ -38,40 +37,22 @@ func getDefaultAfterInterceptor(bot TipBot) []intercept.Func { return []intercept.Func{} } -// registerHandlerWithInterceptor will register a handler with all the predefined interceptors, based on the interceptor type -func (bot TipBot) registerHandlerWithInterceptor(h Handler) { +// registerHandlerWithInterceptor will register a ctx with all the predefined interceptors, based on the interceptor type +func (bot TipBot) registerHandlerWithInterceptor(h InterceptionWrapper) { h.Interceptor.Before = append(getDefaultBeforeInterceptor(bot), h.Interceptor.Before...) //h.Interceptor.After = append(h.Interceptor.After, getDefaultAfterInterceptor(bot)...) //h.Interceptor.OnDefer = append(h.Interceptor.OnDefer, getDefaultDeferInterceptor(bot)...) - - switch h.Interceptor.Type { - case MessageInterceptor: - for _, endpoint := range h.Endpoints { - bot.handle(endpoint, intercept.HandlerWithMessage(h.Handler.(func(ctx context.Context, query *tb.Message) (context.Context, error)), - intercept.WithBeforeMessage(h.Interceptor.Before...), - intercept.WithAfterMessage(h.Interceptor.After...), - intercept.WithDeferMessage(h.Interceptor.OnDefer...))) - } - case QueryInterceptor: - for _, endpoint := range h.Endpoints { - bot.handle(endpoint, intercept.HandlerWithQuery(h.Handler.(func(ctx context.Context, query *tb.Query) (context.Context, error)), - intercept.WithBeforeQuery(h.Interceptor.Before...), - intercept.WithAfterQuery(h.Interceptor.After...), - intercept.WithDeferQuery(h.Interceptor.OnDefer...))) - } - case CallbackInterceptor: - for _, endpoint := range h.Endpoints { - bot.handle(endpoint, intercept.HandlerWithCallback(h.Handler.(func(ctx context.Context, callback *tb.Callback) (context.Context, error)), - intercept.WithBeforeCallback(h.Interceptor.Before...), - intercept.WithAfterCallback(h.Interceptor.After...), - intercept.WithDeferCallback(append(h.Interceptor.OnDefer, bot.answerCallbackInterceptor)...))) - } + for _, endpoint := range h.Endpoints { + bot.handle(endpoint, intercept.WithHandler(h.Handler, + intercept.WithBefore(h.Interceptor.Before...), + intercept.WithAfter(h.Interceptor.After...), + intercept.WithDefer(h.Interceptor.OnDefer...))) } } // handle accepts an endpoint and handler for Telegram handler registration. // function will automatically register string handlers as uppercase and first letter uppercase. -func (bot TipBot) handle(endpoint interface{}, handler interface{}) { +func (bot TipBot) handle(endpoint interface{}, handler tb.HandlerFunc) { // register the endpoint bot.Telegram.Handle(endpoint, handler) switch endpoint.(type) { @@ -90,24 +71,23 @@ func (bot TipBot) handle(endpoint interface{}, handler interface{}) { } // register registers a handler, so that Telegram can handle the endpoint correctly. -func (bot TipBot) register(h Handler) { +func (bot TipBot) register(h InterceptionWrapper) { if h.Interceptor != nil { bot.registerHandlerWithInterceptor(h) } else { for _, endpoint := range h.Endpoints { - bot.handle(endpoint, h.Handler) + bot.handle(endpoint, intercept.WithHandler(h.Handler)) } } } // getHandler returns a list of all handlers, that need to be registered with Telegram -func (bot TipBot) getHandler() []Handler { - return []Handler{ +func (bot TipBot) getHandler() []InterceptionWrapper { + return []InterceptionWrapper{ { Endpoints: []interface{}{"/start"}, Handler: bot.startHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -123,7 +103,6 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/tip", "/t", "/honk"}, Handler: bot.tipHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -140,7 +119,6 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/pay"}, Handler: bot.payHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -156,7 +134,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/invoice", &btnInvoiceMainMenu}, Handler: bot.invoiceHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -172,7 +150,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/shops"}, Handler: bot.shopsHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.logMessageInterceptor, bot.requireUserInterceptor, @@ -187,7 +165,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/shop"}, Handler: bot.shopHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -203,7 +181,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/balance", &btnBalanceMainMenu}, Handler: bot.balanceHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -219,7 +197,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/send", &btnSendMenuEnter}, Handler: bot.sendHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -236,7 +214,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnSendMainMenu}, Handler: bot.keyboardSendHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -253,7 +231,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/faucet", "/zapfhahn", "/kraan", "/grifo"}, Handler: bot.faucetHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -269,7 +247,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/tipjar", "/spendendose"}, Handler: bot.tipjarHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -285,7 +263,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/help", &btnHelpMainMenu}, Handler: bot.helpHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -301,7 +279,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/basics"}, Handler: bot.basicsHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -317,7 +295,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/donate"}, Handler: bot.donationHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -333,7 +311,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/advanced"}, Handler: bot.advancedHelpHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -349,7 +327,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/link"}, Handler: bot.lndhubHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -365,7 +343,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/lnurl"}, Handler: bot.lnurlHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -382,7 +360,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/group"}, Handler: bot.groupHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.logMessageInterceptor, @@ -398,7 +376,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{"/join"}, Handler: bot.groupRequestJoinHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.requirePrivateChatInterceptor, bot.localizerInterceptor, @@ -415,7 +393,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnPayTicket}, Handler: bot.groupConfirmPayButtonHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -430,7 +408,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{tb.OnPhoto}, Handler: bot.photoHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.requirePrivateChatInterceptor, bot.localizerInterceptor, @@ -447,7 +425,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{tb.OnDocument, tb.OnVideo, tb.OnAnimation, tb.OnVoice, tb.OnAudio, tb.OnSticker, tb.OnVideoNote}, Handler: bot.fileHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.requirePrivateChatInterceptor, bot.logMessageInterceptor, @@ -457,7 +435,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{tb.OnText}, Handler: bot.anyTextHandler, Interceptor: &Interceptor{ - Type: MessageInterceptor, + Before: []intercept.Func{ bot.requirePrivateChatInterceptor, // Respond to any text only in private chat bot.localizerInterceptor, @@ -474,7 +452,6 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{tb.OnQuery}, Handler: bot.anyQueryHandler, Interceptor: &Interceptor{ - Type: QueryInterceptor, Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -486,14 +463,14 @@ func (bot TipBot) getHandler() []Handler { }, }, { - Endpoints: []interface{}{tb.OnChosenInlineResult}, + Endpoints: []interface{}{tb.OnInlineResult}, Handler: bot.anyChosenInlineHandler, }, { Endpoints: []interface{}{&btnPay}, Handler: bot.confirmPayHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -508,7 +485,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnCancelPay}, Handler: bot.cancelPaymentHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -523,7 +500,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnSend}, Handler: bot.confirmSendHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -538,7 +515,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnCancelSend}, Handler: bot.cancelSendHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -553,7 +530,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnAcceptInlineSend}, Handler: bot.acceptInlineSendHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -568,7 +545,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnCancelInlineSend}, Handler: bot.cancelInlineSendHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -583,7 +560,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnAcceptInlineReceive}, Handler: bot.acceptInlineReceiveHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -598,7 +575,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnCancelInlineReceive}, Handler: bot.cancelInlineReceiveHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -613,7 +590,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnAcceptInlineFaucet}, Handler: bot.acceptInlineFaucetHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.singletonCallbackInterceptor, bot.localizerInterceptor, @@ -629,7 +606,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnCancelInlineFaucet}, Handler: bot.cancelInlineFaucetHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -644,7 +621,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnAcceptInlineTipjar}, Handler: bot.acceptInlineTipjarHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -659,7 +636,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnCancelInlineTipjar}, Handler: bot.cancelInlineTipjarHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -674,7 +651,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnWithdraw}, Handler: bot.confirmWithdrawHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -689,7 +666,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnCancelWithdraw}, Handler: bot.cancelWithdrawHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -704,7 +681,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnAuth}, Handler: bot.confirmLnurlAuthHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -719,7 +696,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&btnCancelAuth}, Handler: bot.cancelLnurlAuthHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.requireUserInterceptor, @@ -734,7 +711,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopNewShopButton}, Handler: bot.shopNewShopHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -748,7 +725,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopAddItemButton}, Handler: bot.shopNewItemHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -762,7 +739,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopBuyitemButton}, Handler: bot.shopGetItemFilesHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -776,7 +753,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopNextitemButton}, Handler: bot.shopNextItemButtonHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -790,7 +767,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&browseShopButton}, Handler: bot.shopsBrowser, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -804,7 +781,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopSelectButton}, Handler: bot.shopSelect, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -819,7 +796,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopDeleteShopButton}, Handler: bot.shopsDeleteShopBrowser, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -834,7 +811,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopDeleteSelectButton}, Handler: bot.shopSelectDelete, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -849,7 +826,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopLinkShopButton}, Handler: bot.shopsLinkShopBrowser, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -864,7 +841,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopLinkSelectButton}, Handler: bot.shopSelectLink, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -879,7 +856,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopRenameShopButton}, Handler: bot.shopsRenameShopBrowser, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -894,7 +871,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopRenameSelectButton}, Handler: bot.shopSelectRename, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -909,7 +886,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopSettingsButton}, Handler: bot.shopSettingsHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -924,7 +901,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopDescriptionShopButton}, Handler: bot.shopsDescriptionHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -939,7 +916,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopResetShopButton}, Handler: bot.shopsResetHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -953,7 +930,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopResetShopAskButton}, Handler: bot.shopsAskDeleteAllShopsHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -967,7 +944,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopPrevitemButton}, Handler: bot.shopPrevItemButtonHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -981,7 +958,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopShopsButton}, Handler: bot.shopsHandlerCallback, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -996,7 +973,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopItemSettingsButton}, Handler: bot.shopItemSettingsHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -1010,7 +987,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopItemSettingsBackButton}, Handler: bot.displayShopItemHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -1024,7 +1001,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopItemDeleteButton}, Handler: bot.shopItemDeleteHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -1038,7 +1015,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopItemPriceButton}, Handler: bot.shopItemPriceHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -1052,7 +1029,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopItemTitleButton}, Handler: bot.shopItemTitleHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -1066,7 +1043,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopItemAddFileButton}, Handler: bot.shopItemAddItemHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -1080,7 +1057,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopItemBuyButton}, Handler: bot.shopConfirmBuyHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, @@ -1094,7 +1071,7 @@ func (bot TipBot) getHandler() []Handler { Endpoints: []interface{}{&shopItemCancelBuyButton}, Handler: bot.displayShopItemHandler, Interceptor: &Interceptor{ - Type: CallbackInterceptor, + Before: []intercept.Func{ bot.localizerInterceptor, bot.loadUserInterceptor, diff --git a/internal/telegram/help.go b/internal/telegram/help.go index e947ec8..f468e70 100644 --- a/internal/telegram/help.go +++ b/internal/telegram/help.go @@ -3,8 +3,9 @@ package telegram import ( "context" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) func (bot TipBot) makeHelpMessage(ctx context.Context, m *tb.Message) string { @@ -26,25 +27,25 @@ func (bot TipBot) makeHelpMessage(ctx context.Context, m *tb.Message) string { return fmt.Sprintf(helpMessage, dynamicHelpMessage) } -func (bot TipBot) helpHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot TipBot) helpHandler(ctx intercept.Context) (intercept.Context, error) { // check and print all commands - bot.anyTextHandler(ctx, m) - if !m.Private() { + bot.anyTextHandler(ctx) + if !ctx.Message().Private() { // delete message - bot.tryDeleteMessage(m) + bot.tryDeleteMessage(ctx.Message()) } - bot.trySendMessage(m.Sender, bot.makeHelpMessage(ctx, m), tb.NoPreview) + bot.trySendMessage(ctx.Sender(), bot.makeHelpMessage(ctx, ctx.Message()), tb.NoPreview) return ctx, nil } -func (bot TipBot) basicsHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot TipBot) basicsHandler(ctx intercept.Context) (intercept.Context, error) { // check and print all commands - bot.anyTextHandler(ctx, m) - if !m.Private() { + bot.anyTextHandler(ctx) + if !ctx.Message().Private() { // delete message - bot.tryDeleteMessage(m) + bot.tryDeleteMessage(ctx.Message()) } - bot.trySendMessage(m.Sender, Translate(ctx, "basicsMessage"), tb.NoPreview) + bot.trySendMessage(ctx.Sender(), Translate(ctx, "basicsMessage"), tb.NoPreview) return ctx, nil } @@ -74,13 +75,13 @@ func (bot TipBot) makeAdvancedHelpMessage(ctx context.Context, m *tb.Message) st ) } -func (bot TipBot) advancedHelpHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot TipBot) advancedHelpHandler(ctx intercept.Context) (intercept.Context, error) { // check and print all commands - bot.anyTextHandler(ctx, m) - if !m.Private() { + bot.anyTextHandler(ctx) + if !ctx.Message().Private() { // delete message - bot.tryDeleteMessage(m) + bot.tryDeleteMessage(ctx.Message()) } - bot.trySendMessage(m.Sender, bot.makeAdvancedHelpMessage(ctx, m), tb.NoPreview) + bot.trySendMessage(ctx.Sender(), bot.makeAdvancedHelpMessage(ctx, ctx.Message()), tb.NoPreview) return ctx, nil } diff --git a/internal/telegram/inline_query.go b/internal/telegram/inline_query.go index a99ecb5..0c8ebc4 100644 --- a/internal/telegram/inline_query.go +++ b/internal/telegram/inline_query.go @@ -7,18 +7,20 @@ import ( "strconv" "strings" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" + "github.com/LightningTipBot/LightningTipBot/internal/runtime" "github.com/LightningTipBot/LightningTipBot/internal/storage" "github.com/LightningTipBot/LightningTipBot/internal/i18n" i18n2 "github.com/nicksnyder/go-i18n/v2/i18n" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) const queryImage = "https://avatars.githubusercontent.com/u/88730856?v=4" -func (bot TipBot) inlineQueryInstructions(ctx context.Context, q *tb.Query) (context.Context, error) { +func (bot TipBot) inlineQueryInstructions(ctx intercept.Context) (intercept.Context, error) { instructions := []struct { url string title string @@ -60,11 +62,11 @@ func (bot TipBot) inlineQueryInstructions(ctx context.Context, q *tb.Query) (con results[i].SetResultID(strconv.Itoa(i)) } - err := bot.Telegram.Answer(q, &tb.QueryResponse{ + err := ctx.Answer(&tb.QueryResponse{ Results: results, CacheTime: 5, // a minute IsPersonal: true, - QueryID: q.ID, + QueryID: ctx.Query().ID, }) if err != nil { @@ -73,7 +75,7 @@ func (bot TipBot) inlineQueryInstructions(ctx context.Context, q *tb.Query) (con return ctx, err } -func (bot TipBot) inlineQueryReplyWithError(q *tb.Query, message string, help string) { +func (bot TipBot) inlineQueryReplyWithError(ctx intercept.Context, message string, help string) { results := make(tb.Results, 1) // []tb.Result result := &tb.ArticleResult{ // URL: url, @@ -83,11 +85,12 @@ func (bot TipBot) inlineQueryReplyWithError(q *tb.Query, message string, help st // required for photos ThumbURL: queryImage, } - id := fmt.Sprintf("inl-error-%d-%s", q.From.ID, RandStringRunes(5)) + id := fmt.Sprintf("inl-error-%d-%s", ctx.Query().Sender.ID, RandStringRunes(5)) result.SetResultID(id) results[0] = result - err := bot.Telegram.Answer(q, &tb.QueryResponse{ - Results: results, + err := ctx.Answer(&tb.QueryResponse{ + Results: results, + CacheTime: 1, // 60 == 1 minute, todo: make higher than 1 s in production }) @@ -98,21 +101,22 @@ func (bot TipBot) inlineQueryReplyWithError(q *tb.Query, message string, help st // anyChosenInlineHandler will load any inline object from cache and store into bunt. // this is used to decrease bunt db write ops. -func (bot TipBot) anyChosenInlineHandler(q *tb.ChosenInlineResult) { +func (bot TipBot) anyChosenInlineHandler(ctx intercept.Context) (intercept.Context, error) { // load inline object from cache - inlineObject, err := bot.Cache.Get(q.ResultID) + inlineObject, err := bot.Cache.Get(ctx.InlineResult().ResultID) // check error if err != nil { log.Errorf("[anyChosenInlineHandler] could not find inline object in cache. %v", err.Error()) - return + return ctx, err } switch inlineObject.(type) { case storage.Storable: // persist inline object in bunt runtime.IgnoreError(bot.Bunt.Set(inlineObject.(storage.Storable))) default: - log.Errorf("[anyChosenInlineHandler] invalid inline object type: %s, query: %s", reflect.TypeOf(inlineObject).String(), q.Query) + log.Errorf("[anyChosenInlineHandler] invalid inline object type: %s, query: %s", reflect.TypeOf(inlineObject).String(), ctx.InlineResult().Query) } + return ctx, nil } func (bot TipBot) commandTranslationMap(ctx context.Context, command string) context.Context { @@ -134,36 +138,37 @@ func (bot TipBot) commandTranslationMap(ctx context.Context, command string) con return ctx } -func (bot TipBot) anyQueryHandler(ctx context.Context, q *tb.Query) (context.Context, error) { - if q.Text == "" { - return bot.inlineQueryInstructions(ctx, q) +func (bot TipBot) anyQueryHandler(ctx intercept.Context) (intercept.Context, error) { + if ctx.Query().Text == "" { + return bot.inlineQueryInstructions(ctx) } // create the inline send result - if strings.HasPrefix(q.Text, "/") { - q.Text = strings.TrimPrefix(q.Text, "/") + var text = ctx.Query().Text + if strings.HasPrefix(text, "/") { + text = strings.TrimPrefix(text, "/") } - if strings.HasPrefix(q.Text, "send") || strings.HasPrefix(q.Text, "pay") { - return bot.handleInlineSendQuery(ctx, q) + if strings.HasPrefix(text, "send") || strings.HasPrefix(text, "pay") { + return bot.handleInlineSendQuery(ctx) } - if strings.HasPrefix(q.Text, "faucet") || strings.HasPrefix(q.Text, "zapfhahn") || strings.HasPrefix(q.Text, "kraan") || strings.HasPrefix(q.Text, "grifo") { - if len(strings.Split(q.Text, " ")) > 1 { - c := strings.Split(q.Text, " ")[0] - ctx = bot.commandTranslationMap(ctx, c) + if strings.HasPrefix(text, "faucet") || strings.HasPrefix(text, "zapfhahn") || strings.HasPrefix(text, "kraan") || strings.HasPrefix(text, "grifo") { + if len(strings.Split(text, " ")) > 1 { + c := strings.Split(text, " ")[0] + ctx.Context = bot.commandTranslationMap(ctx, c) } - return bot.handleInlineFaucetQuery(ctx, q) + return bot.handleInlineFaucetQuery(ctx) } - if strings.HasPrefix(q.Text, "tipjar") || strings.HasPrefix(q.Text, "spendendose") { - if len(strings.Split(q.Text, " ")) > 1 { - c := strings.Split(q.Text, " ")[0] - ctx = bot.commandTranslationMap(ctx, c) + if strings.HasPrefix(text, "tipjar") || strings.HasPrefix(text, "spendendose") { + if len(strings.Split(text, " ")) > 1 { + c := strings.Split(text, " ")[0] + ctx.Context = bot.commandTranslationMap(ctx, c) } - return bot.handleInlineTipjarQuery(ctx, q) + return bot.handleInlineTipjarQuery(ctx) } - if strings.HasPrefix(q.Text, "receive") || strings.HasPrefix(q.Text, "get") || strings.HasPrefix(q.Text, "payme") || strings.HasPrefix(q.Text, "request") { - return bot.handleInlineReceiveQuery(ctx, q) + if strings.HasPrefix(text, "receive") || strings.HasPrefix(text, "get") || strings.HasPrefix(text, "payme") || strings.HasPrefix(text, "request") { + return bot.handleInlineReceiveQuery(ctx) } return ctx, nil } diff --git a/internal/telegram/inline_receive.go b/internal/telegram/inline_receive.go index aa68533..7b65e5d 100644 --- a/internal/telegram/inline_receive.go +++ b/internal/telegram/inline_receive.go @@ -4,10 +4,12 @@ import ( "bytes" "context" "fmt" - "github.com/LightningTipBot/LightningTipBot/internal/errors" "strings" "time" + "github.com/LightningTipBot/LightningTipBot/internal/errors" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" + "github.com/LightningTipBot/LightningTipBot/internal/runtime/mutex" "github.com/LightningTipBot/LightningTipBot/internal/storage" @@ -19,11 +21,11 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/runtime" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) var ( - inlineReceiveMenu = &tb.ReplyMarkup{ResizeReplyKeyboard: true} + inlineReceiveMenu = &tb.ReplyMarkup{ResizeKeyboard: true} btnCancelInlineReceive = inlineReceiveMenu.Data("đŸšĢ Cancel", "cancel_receive_inline") btnAcceptInlineReceive = inlineReceiveMenu.Data("💸 Pay", "confirm_receive_inline") ) @@ -31,7 +33,7 @@ var ( type InlineReceive struct { *storage.Base MessageText string `json:"inline_receive_messagetext"` - Message *tb.Message `json:"inline_receive_message"` + Message tb.Editable `json:"inline_receive_message"` Amount int64 `json:"inline_receive_amount"` From *lnbits.User `json:"inline_receive_from"` To *lnbits.User `json:"inline_receive_to"` @@ -41,7 +43,7 @@ type InlineReceive struct { } func (bot TipBot) makeReceiveKeyboard(ctx context.Context, id string) *tb.ReplyMarkup { - inlineReceiveMenu := &tb.ReplyMarkup{ResizeReplyKeyboard: true} + inlineReceiveMenu := &tb.ReplyMarkup{ResizeKeyboard: true} acceptInlineReceiveButton := inlineReceiveMenu.Data(Translate(ctx, "payReceiveButtonMessage"), "confirm_receive_inline") cancelInlineReceiveButton := inlineReceiveMenu.Data(Translate(ctx, "cancelButtonMessage"), "cancel_receive_inline") acceptInlineReceiveButton.Data = id @@ -55,18 +57,19 @@ func (bot TipBot) makeReceiveKeyboard(ctx context.Context, id string) *tb.ReplyM return inlineReceiveMenu } -func (bot TipBot) handleInlineReceiveQuery(ctx context.Context, q *tb.Query) (context.Context, error) { +func (bot TipBot) handleInlineReceiveQuery(ctx intercept.Context) (intercept.Context, error) { + q := ctx.Query() to := LoadUser(ctx) amount, err := decodeAmountFromCommand(q.Text) if err != nil { - bot.inlineQueryReplyWithError(q, Translate(ctx, "inlineQueryReceiveTitle"), fmt.Sprintf(Translate(ctx, "inlineQueryReceiveDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, Translate(ctx, "inlineQueryReceiveTitle"), fmt.Sprintf(Translate(ctx, "inlineQueryReceiveDescription"), bot.Telegram.Me.Username)) return ctx, err } if amount < 1 { - bot.inlineQueryReplyWithError(q, Translate(ctx, "inlineSendInvalidAmountMessage"), fmt.Sprintf(Translate(ctx, "inlineQueryReceiveDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, Translate(ctx, "inlineSendInvalidAmountMessage"), fmt.Sprintf(Translate(ctx, "inlineQueryReceiveDescription"), bot.Telegram.Me.Username)) return ctx, errors.Create(errors.InvalidAmountError) } - toUserStr := GetUserStr(&q.From) + toUserStr := GetUserStr(q.Sender) // check whether the 3rd argument is a username // command is "@LightningTipBot receive 123 @from_user This is the memo" @@ -80,7 +83,7 @@ func (bot TipBot) handleInlineReceiveQuery(ctx context.Context, q *tb.Query) (co if err != nil { //bot.tryDeleteMessage(m) //bot.trySendMessage(m.Sender, fmt.Sprintf(Translate(ctx, "sendUserHasNoWalletMessage"), toUserStrMention)) - bot.inlineQueryReplyWithError(q, + bot.inlineQueryReplyWithError(ctx, fmt.Sprintf(TranslateUser(ctx, "sendUserHasNoWalletMessage"), from_username), fmt.Sprintf(TranslateUser(ctx, "inlineQueryReceiveDescription"), bot.Telegram.Me.Username)) @@ -116,8 +119,8 @@ func (bot TipBot) handleInlineReceiveQuery(ctx context.Context, q *tb.Query) (co // required for photos ThumbURL: url, } - id := fmt.Sprintf("inl-receive-%d-%d-%s", q.From.ID, amount, RandStringRunes(5)) - result.ReplyMarkup = &tb.InlineKeyboardMarkup{InlineKeyboard: bot.makeReceiveKeyboard(ctx, id).InlineKeyboard} + id := fmt.Sprintf("inl-receive-%d-%d-%s", q.Sender.ID, amount, RandStringRunes(5)) + result.ReplyMarkup = &tb.ReplyMarkup{InlineKeyboard: bot.makeReceiveKeyboard(ctx, id).InlineKeyboard} results[i] = result // needed to set a unique string ID for each result results[i].SetResultID(id) @@ -147,7 +150,8 @@ func (bot TipBot) handleInlineReceiveQuery(ctx context.Context, q *tb.Query) (co return ctx, nil } -func (bot *TipBot) acceptInlineReceiveHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) acceptInlineReceiveHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() tx := &InlineReceive{Base: storage.New(storage.ID(c.Data))} // immediatelly set intransaction to block duplicate calls mutex.LockWithContext(ctx, tx.ID) @@ -177,7 +181,7 @@ func (bot *TipBot) acceptInlineReceiveHandler(ctx context.Context, c *tb.Callbac inlineReceive.From = from } - inlineReceive.Message = c.Message + inlineReceive.Message = c runtime.IgnoreError(inlineReceive.Set(inlineReceive, bot.Bunt)) to := inlineReceive.To @@ -196,16 +200,16 @@ func (bot *TipBot) acceptInlineReceiveHandler(ctx context.Context, c *tb.Callbac // if user has no wallet, show invoice bot.tryEditMessage(inlineReceive.Message, inlineReceive.MessageText, &tb.ReplyMarkup{}) // runtime.IgnoreError(inlineReceive.Set(inlineReceive, bot.Bunt)) - bot.inlineReceiveInvoice(ctx, c, inlineReceive) + bot.inlineReceiveInvoice(ctx, inlineReceive) return ctx, errors.Create(errors.BalanceToLowError) } else { // else, do an internal transaction - return bot.sendInlineReceiveHandler(ctx, c) - + return bot.sendInlineReceiveHandler(ctx) } } -func (bot *TipBot) sendInlineReceiveHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) sendInlineReceiveHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() tx := &InlineReceive{Base: storage.New(storage.ID(c.Data))} mutex.LockWithContext(ctx, tx.ID) defer mutex.UnlockWithContext(ctx, tx.ID) @@ -254,17 +258,18 @@ func (bot *TipBot) sendInlineReceiveHandler(ctx context.Context, c *tb.Callback) if !success { errMsg := fmt.Sprintf("[acceptInlineReceiveHandler] Transaction failed: %s", err.Error()) log.Errorln(errMsg) - bot.tryEditMessage(c.Message, i18n.Translate(inlineReceive.LanguageCode, "inlineReceiveFailedMessage"), &tb.ReplyMarkup{}) + bot.tryEditMessage(c, i18n.Translate(inlineReceive.LanguageCode, "inlineReceiveFailedMessage"), &tb.ReplyMarkup{}) return ctx, errors.Create(errors.UnknownError) } log.Infof("[💸 inlineReceive] Send from %s to %s (%d sat).", fromUserStr, toUserStr, inlineReceive.Amount) inlineReceive.Set(inlineReceive, bot.Bunt) - return bot.finishInlineReceiveHandler(ctx, c) + ctx.Context, err = bot.finishInlineReceiveHandler(ctx, ctx.Callback()) + return ctx, err } -func (bot *TipBot) inlineReceiveInvoice(ctx context.Context, c *tb.Callback, inlineReceive *InlineReceive) { +func (bot *TipBot) inlineReceiveInvoice(ctx intercept.Context, inlineReceive *InlineReceive) { if !inlineReceive.Active { log.Errorf("[acceptInlineReceiveHandler] inline receive not active anymore") return @@ -287,13 +292,8 @@ func (bot *TipBot) inlineReceiveInvoice(ctx context.Context, c *tb.Callback, inl } // send the invoice data to user - var msg *tb.Message - if inlineReceive.Message.Chat != nil { - msg = bot.trySendMessage(inlineReceive.Message.Chat, &tb.Photo{File: tb.File{FileReader: bytes.NewReader(qr)}, Caption: fmt.Sprintf("`%s`", invoice.PaymentRequest)}) - } else { - msg = bot.trySendMessage(c.Sender, &tb.Photo{File: tb.File{FileReader: bytes.NewReader(qr)}, Caption: fmt.Sprintf("`%s`", invoice.PaymentRequest)}) - bot.tryEditMessage(inlineReceive.Message, fmt.Sprintf("%s\n\nPay this invoice:\n```%s```", inlineReceive.MessageText, invoice.PaymentRequest)) - } + msg := bot.trySendMessage(ctx.Callback().Sender, &tb.Photo{File: tb.File{FileReader: bytes.NewReader(qr)}, Caption: fmt.Sprintf("`%s`", invoice.PaymentRequest)}) + bot.tryEditMessage(inlineReceive.Message, fmt.Sprintf("%s\n\nPay this invoice:\n```%s```", inlineReceive.MessageText, invoice.PaymentRequest)) invoice.InvoiceMessage = msg runtime.IgnoreError(bot.Bunt.Set(invoice)) log.Printf("[/invoice] Incvoice created. User: %s, amount: %d sat.", GetUserStr(inlineReceive.To.Telegram), inlineReceive.Amount) @@ -309,8 +309,10 @@ func (bot *TipBot) inlineReceiveEvent(event Event) { func (bot *TipBot) finishInlineReceiveHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { tx := &InlineReceive{Base: storage.New(storage.ID(c.Data))} // immediatelly set intransaction to block duplicate calls - mutex.LockWithContext(ctx, tx.ID) - defer mutex.UnlockWithContext(ctx, tx.ID) + if ctx != nil { + mutex.LockWithContext(ctx, tx.ID) + defer mutex.UnlockWithContext(ctx, tx.ID) + } rn, err := tx.Get(tx, bot.Bunt) if err != nil { log.Errorf("[getInlineReceive] %s", err.Error()) @@ -323,7 +325,7 @@ func (bot *TipBot) finishInlineReceiveHandler(ctx context.Context, c *tb.Callbac toUserStrMd := GetUserStrMd(to.Telegram) fromUserStrMd := GetUserStrMd(from.Telegram) toUserStr := GetUserStr(to.Telegram) - inlineReceive.MessageText = fmt.Sprintf("%s", fmt.Sprintf(i18n.Translate(inlineReceive.LanguageCode, "inlineSendUpdateMessageAccept"), inlineReceive.Amount, fromUserStrMd, toUserStrMd)) + inlineReceive.MessageText = fmt.Sprintf(i18n.Translate(inlineReceive.LanguageCode, "inlineSendUpdateMessageAccept"), inlineReceive.Amount, fromUserStrMd, toUserStrMd) memo := inlineReceive.Memo if len(memo) > 0 { inlineReceive.MessageText += fmt.Sprintf(i18n.Translate(inlineReceive.LanguageCode, "inlineReceiveAppendMemo"), memo) @@ -346,7 +348,8 @@ func (bot *TipBot) finishInlineReceiveHandler(ctx context.Context, c *tb.Callbac // inlineReceive.Release(inlineReceive, bot.Bunt) } -func (bot *TipBot) cancelInlineReceiveHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) cancelInlineReceiveHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() tx := &InlineReceive{Base: storage.New(storage.ID(c.Data))} mutex.LockWithContext(ctx, tx.ID) defer mutex.UnlockWithContext(ctx, tx.ID) @@ -360,7 +363,7 @@ func (bot *TipBot) cancelInlineReceiveHandler(ctx context.Context, c *tb.Callbac if c.Sender.ID != inlineReceive.To.Telegram.ID { return ctx, errors.Create(errors.UnknownError) } - bot.tryEditMessage(c.Message, i18n.Translate(inlineReceive.LanguageCode, "inlineReceiveCancelledMessage"), &tb.ReplyMarkup{}) + bot.tryEditMessage(c, i18n.Translate(inlineReceive.LanguageCode, "inlineReceiveCancelledMessage"), &tb.ReplyMarkup{}) // set the inlineReceive inactive inlineReceive.Active = false return ctx, inlineReceive.Set(inlineReceive, bot.Bunt) diff --git a/internal/telegram/inline_send.go b/internal/telegram/inline_send.go index a66b1e3..eb28a98 100644 --- a/internal/telegram/inline_send.go +++ b/internal/telegram/inline_send.go @@ -3,10 +3,12 @@ package telegram import ( "context" "fmt" - "github.com/LightningTipBot/LightningTipBot/internal/errors" "strings" "time" + "github.com/LightningTipBot/LightningTipBot/internal/errors" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" + "github.com/LightningTipBot/LightningTipBot/internal/runtime/mutex" "github.com/LightningTipBot/LightningTipBot/internal/storage" @@ -17,11 +19,11 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/lnbits" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) var ( - inlineSendMenu = &tb.ReplyMarkup{ResizeReplyKeyboard: true} + inlineSendMenu = &tb.ReplyMarkup{ResizeKeyboard: true} btnCancelInlineSend = inlineSendMenu.Data("đŸšĢ Cancel", "cancel_send_inline") btnAcceptInlineSend = inlineSendMenu.Data("✅ Receive", "confirm_send_inline") ) @@ -38,7 +40,7 @@ type InlineSend struct { } func (bot TipBot) makeSendKeyboard(ctx context.Context, id string) *tb.ReplyMarkup { - inlineSendMenu := &tb.ReplyMarkup{ResizeReplyKeyboard: true} + inlineSendMenu := &tb.ReplyMarkup{ResizeKeyboard: true} acceptInlineSendButton := inlineSendMenu.Data(Translate(ctx, "receiveButtonMessage"), "confirm_send_inline") cancelInlineSendButton := inlineSendMenu.Data(Translate(ctx, "cancelButtonMessage"), "cancel_send_inline") acceptInlineSendButton.Data = id @@ -52,20 +54,21 @@ func (bot TipBot) makeSendKeyboard(ctx context.Context, id string) *tb.ReplyMark return inlineSendMenu } -func (bot TipBot) handleInlineSendQuery(ctx context.Context, q *tb.Query) (context.Context, error) { +func (bot TipBot) handleInlineSendQuery(ctx intercept.Context) (intercept.Context, error) { + q := ctx.Query() // inlineSend := NewInlineSend() // var err error amount, err := decodeAmountFromCommand(q.Text) if err != nil { - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineQuerySendTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQuerySendDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineQuerySendTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQuerySendDescription"), bot.Telegram.Me.Username)) return ctx, err } if amount < 1 { - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineSendInvalidAmountMessage"), fmt.Sprintf(Translate(ctx, "inlineQuerySendDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineSendInvalidAmountMessage"), fmt.Sprintf(Translate(ctx, "inlineQuerySendDescription"), bot.Telegram.Me.Username)) return ctx, errors.Create(errors.InvalidAmountError) } fromUser := LoadUser(ctx) - fromUserStr := GetUserStr(&q.From) + fromUserStr := GetUserStr(q.Sender) balance, err := bot.GetUserBalanceCached(fromUser) if err != nil { errmsg := fmt.Sprintf("could not get balance of user %s", fromUserStr) @@ -75,7 +78,7 @@ func (bot TipBot) handleInlineSendQuery(ctx context.Context, q *tb.Query) (conte // check if fromUser has balance if balance < amount { log.Errorf("Balance of user %s too low", fromUserStr) - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineSendBalanceLowMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQuerySendDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineSendBalanceLowMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQuerySendDescription"), bot.Telegram.Me.Username)) return ctx, errors.Create(errors.InvalidAmountError) } @@ -91,7 +94,7 @@ func (bot TipBot) handleInlineSendQuery(ctx context.Context, q *tb.Query) (conte if err != nil { //bot.tryDeleteMessage(m) //bot.trySendMessage(m.Sender, fmt.Sprintf(Translate(ctx, "sendUserHasNoWalletMessage"), toUserStrMention)) - bot.inlineQueryReplyWithError(q, + bot.inlineQueryReplyWithError(ctx, fmt.Sprintf(TranslateUser(ctx, "sendUserHasNoWalletMessage"), to_username), fmt.Sprintf(TranslateUser(ctx, "inlineQuerySendDescription"), bot.Telegram.Me.Username)) @@ -127,8 +130,8 @@ func (bot TipBot) handleInlineSendQuery(ctx context.Context, q *tb.Query) (conte // required for photos ThumbURL: url, } - id := fmt.Sprintf("inl-send-%d-%d-%s", q.From.ID, amount, RandStringRunes(5)) - result.ReplyMarkup = &tb.InlineKeyboardMarkup{InlineKeyboard: bot.makeSendKeyboard(ctx, id).InlineKeyboard} + id := fmt.Sprintf("inl-send-%d-%d-%s", q.Sender.ID, amount, RandStringRunes(5)) + result.ReplyMarkup = &tb.ReplyMarkup{InlineKeyboard: bot.makeSendKeyboard(ctx, id).InlineKeyboard} results[i] = result // needed to set a unique string ID for each result results[i].SetResultID(id) @@ -161,7 +164,8 @@ func (bot TipBot) handleInlineSendQuery(ctx context.Context, q *tb.Query) (conte return ctx, nil } -func (bot *TipBot) acceptInlineSendHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) acceptInlineSendHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() to := LoadUser(ctx) tx := &InlineSend{Base: storage.New(storage.ID(c.Data))} mutex.LockWithContext(ctx, tx.ID) @@ -227,7 +231,7 @@ func (bot *TipBot) acceptInlineSendHandler(ctx context.Context, c *tb.Callback) if !success { errMsg := fmt.Sprintf("[sendInline] Transaction failed: %s", err.Error()) log.Errorln(errMsg) - bot.tryEditMessage(c.Message, i18n.Translate(inlineSend.LanguageCode, "inlineSendFailedMessage"), &tb.ReplyMarkup{}) + bot.tryEditMessage(c, i18n.Translate(inlineSend.LanguageCode, "inlineSendFailedMessage"), &tb.ReplyMarkup{}) return ctx, errors.Create(errors.UnknownError) } @@ -241,7 +245,7 @@ func (bot *TipBot) acceptInlineSendHandler(ctx context.Context, c *tb.Callback) if !to.Initialized { inlineSend.Message += "\n\n" + fmt.Sprintf(i18n.Translate(inlineSend.LanguageCode, "inlineSendCreateWalletMessage"), GetUserStrMd(bot.Telegram.Me)) } - bot.tryEditMessage(c.Message, inlineSend.Message, &tb.ReplyMarkup{}) + bot.tryEditMessage(c, inlineSend.Message, &tb.ReplyMarkup{}) // notify users bot.trySendMessage(to.Telegram, fmt.Sprintf(i18n.Translate(to.Telegram.LanguageCode, "sendReceivedMessage"), fromUserStrMd, amount)) bot.trySendMessage(fromUser.Telegram, fmt.Sprintf(i18n.Translate(fromUser.Telegram.LanguageCode, "sendSentMessage"), amount, toUserStrMd)) @@ -252,7 +256,8 @@ func (bot *TipBot) acceptInlineSendHandler(ctx context.Context, c *tb.Callback) return ctx, nil } -func (bot *TipBot) cancelInlineSendHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) cancelInlineSendHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() tx := &InlineSend{Base: storage.New(storage.ID(c.Data))} mutex.LockWithContext(ctx, tx.ID) defer mutex.UnlockWithContext(ctx, tx.ID) @@ -266,7 +271,7 @@ func (bot *TipBot) cancelInlineSendHandler(ctx context.Context, c *tb.Callback) if c.Sender.ID != inlineSend.From.Telegram.ID { return ctx, errors.Create(errors.UnknownError) } - bot.tryEditMessage(c.Message, i18n.Translate(inlineSend.LanguageCode, "sendCancelledMessage"), &tb.ReplyMarkup{}) + bot.tryEditMessage(c, i18n.Translate(inlineSend.LanguageCode, "sendCancelledMessage"), &tb.ReplyMarkup{}) // set the inlineSend inactive inlineSend.Active = false return ctx, inlineSend.Set(inlineSend, bot.Bunt) diff --git a/internal/telegram/intercept/callback.go b/internal/telegram/intercept/callback.go deleted file mode 100644 index ea00e09..0000000 --- a/internal/telegram/intercept/callback.go +++ /dev/null @@ -1,77 +0,0 @@ -package intercept - -import ( - "context" - - log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" -) - -type CallbackFuncHandler func(ctx context.Context, message *tb.Callback) (context.Context, error) -type Func func(ctx context.Context, message interface{}) (context.Context, error) - -type handlerCallbackInterceptor struct { - handler CallbackFuncHandler - before CallbackChain - after CallbackChain - onDefer CallbackChain -} -type CallbackChain []Func -type CallbackInterceptOption func(*handlerCallbackInterceptor) - -func WithBeforeCallback(chain ...Func) CallbackInterceptOption { - return func(a *handlerCallbackInterceptor) { - a.before = chain - } -} -func WithAfterCallback(chain ...Func) CallbackInterceptOption { - return func(a *handlerCallbackInterceptor) { - a.after = chain - } -} -func WithDeferCallback(chain ...Func) CallbackInterceptOption { - return func(a *handlerCallbackInterceptor) { - a.onDefer = chain - } -} - -func interceptCallback(ctx context.Context, message *tb.Callback, hm CallbackChain) (context.Context, error) { - if ctx == nil { - ctx = context.Background() - } - if hm != nil { - var err error - for _, m := range hm { - ctx, err = m(ctx, message) - if err != nil { - return ctx, err - } - } - } - return ctx, nil -} - -func HandlerWithCallback(handler CallbackFuncHandler, option ...CallbackInterceptOption) func(Callback *tb.Callback) { - hm := &handlerCallbackInterceptor{handler: handler} - for _, opt := range option { - opt(hm) - } - return func(c *tb.Callback) { - ctx := context.Background() - ctx, err := interceptCallback(ctx, c, hm.before) - if err != nil { - log.Traceln(err) - return - } - defer interceptCallback(ctx, c, hm.onDefer) - ctx, err = hm.handler(ctx, c) - if err != nil { - log.Traceln(err) - return - } - _, err = interceptCallback(ctx, c, hm.after) - if err != nil { - log.Traceln(err) - } - } -} diff --git a/internal/telegram/intercept/context.go b/internal/telegram/intercept/context.go new file mode 100644 index 0000000..39e3bb0 --- /dev/null +++ b/internal/telegram/intercept/context.go @@ -0,0 +1,84 @@ +package intercept + +import ( + "context" + + log "github.com/sirupsen/logrus" + tb "gopkg.in/lightningtipbot/telebot.v3" +) + +type Context struct { + context.Context + TeleContext +} +type TeleContext struct { + tb.Context +} + +type Func func(ctx Context) (Context, error) + +type handlerInterceptor struct { + handler Func + before Chain + after Chain + onDefer Chain +} +type Chain []Func +type Option func(*handlerInterceptor) + +func WithBefore(chain ...Func) Option { + return func(a *handlerInterceptor) { + a.before = chain + } +} +func WithAfter(chain ...Func) Option { + return func(a *handlerInterceptor) { + a.after = chain + } +} +func WithDefer(chain ...Func) Option { + return func(a *handlerInterceptor) { + a.onDefer = chain + } +} + +func intercept(h Context, hm Chain) (Context, error) { + + if hm != nil { + var err error + for _, m := range hm { + h, err = m(h) + if err != nil { + return h, err + } + } + } + return h, nil +} + +func WithHandler(handler Func, option ...Option) tb.HandlerFunc { + hm := &handlerInterceptor{handler: handler} + for _, opt := range option { + opt(hm) + } + return func(c tb.Context) error { + h := Context{TeleContext: TeleContext{Context: c}, Context: context.Background()} + h, err := intercept(h, hm.before) + if err != nil { + log.Traceln(err) + return err + } + defer intercept(h, hm.onDefer) + h, err = hm.handler(h) + if err != nil { + log.Traceln(err) + return err + } + _, err = intercept(h, hm.after) + if err != nil { + log.Traceln(err) + return err + } + return nil + } +} diff --git a/internal/telegram/intercept/message.go b/internal/telegram/intercept/message.go deleted file mode 100644 index c6c3f3c..0000000 --- a/internal/telegram/intercept/message.go +++ /dev/null @@ -1,77 +0,0 @@ -package intercept - -import ( - "context" - - log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" -) - -type MessageFuncHandler func(ctx context.Context, message *tb.Message) (context.Context, error) - -type handlerMessageInterceptor struct { - handler MessageFuncHandler - before MessageChain - after MessageChain - onDefer MessageChain -} -type MessageChain []Func -type MessageInterceptOption func(*handlerMessageInterceptor) - -func WithBeforeMessage(chain ...Func) MessageInterceptOption { - return func(a *handlerMessageInterceptor) { - a.before = chain - } -} -func WithAfterMessage(chain ...Func) MessageInterceptOption { - return func(a *handlerMessageInterceptor) { - a.after = chain - } -} -func WithDeferMessage(chain ...Func) MessageInterceptOption { - return func(a *handlerMessageInterceptor) { - a.onDefer = chain - } -} - -func interceptMessage(ctx context.Context, message *tb.Message, hm MessageChain) (context.Context, error) { - if ctx == nil { - ctx = context.Background() - } - if hm != nil { - var err error - for _, m := range hm { - ctx, err = m(ctx, message) - if err != nil { - return ctx, err - } - } - } - return ctx, nil -} - -func HandlerWithMessage(handler MessageFuncHandler, option ...MessageInterceptOption) func(message *tb.Message) { - hm := &handlerMessageInterceptor{handler: handler} - for _, opt := range option { - opt(hm) - } - return func(message *tb.Message) { - ctx := context.Background() - ctx, err := interceptMessage(ctx, message, hm.before) - if err != nil { - log.Traceln(err) - return - } - defer interceptMessage(ctx, message, hm.onDefer) - ctx, err = hm.handler(ctx, message) - if err != nil { - log.Traceln(err) - return - } - _, err = interceptMessage(ctx, message, hm.after) - if err != nil { - log.Traceln(err) - return - } - } -} diff --git a/internal/telegram/intercept/query.go b/internal/telegram/intercept/query.go deleted file mode 100644 index 6aa8a6d..0000000 --- a/internal/telegram/intercept/query.go +++ /dev/null @@ -1,77 +0,0 @@ -package intercept - -import ( - "context" - - log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" -) - -type QueryFuncHandler func(ctx context.Context, message *tb.Query) (context.Context, error) - -type handlerQueryInterceptor struct { - handler QueryFuncHandler - before QueryChain - after QueryChain - onDefer QueryChain -} -type QueryChain []Func -type QueryInterceptOption func(*handlerQueryInterceptor) - -func WithBeforeQuery(chain ...Func) QueryInterceptOption { - return func(a *handlerQueryInterceptor) { - a.before = chain - } -} -func WithAfterQuery(chain ...Func) QueryInterceptOption { - return func(a *handlerQueryInterceptor) { - a.after = chain - } -} -func WithDeferQuery(chain ...Func) QueryInterceptOption { - return func(a *handlerQueryInterceptor) { - a.onDefer = chain - } -} - -func interceptQuery(ctx context.Context, message *tb.Query, hm QueryChain) (context.Context, error) { - if ctx == nil { - ctx = context.Background() - } - if hm != nil { - var err error - for _, m := range hm { - ctx, err = m(ctx, message) - if err != nil { - return ctx, err - } - } - } - return ctx, nil -} - -func HandlerWithQuery(handler QueryFuncHandler, option ...QueryInterceptOption) func(message *tb.Query) { - hm := &handlerQueryInterceptor{handler: handler} - for _, opt := range option { - opt(hm) - } - return func(query *tb.Query) { - ctx := context.Background() - ctx, err := interceptQuery(context.Background(), query, hm.before) - if err != nil { - log.Traceln(err) - return - } - defer interceptQuery(ctx, query, hm.onDefer) - ctx, err = hm.handler(ctx, query) - if err != nil { - log.Traceln(err) - return - } - _, err = interceptQuery(ctx, query, hm.after) - if err != nil { - log.Traceln(err) - return - } - } -} diff --git a/internal/telegram/interceptor.go b/internal/telegram/interceptor.go index 62ce3a1..3aeb9f8 100644 --- a/internal/telegram/interceptor.go +++ b/internal/telegram/interceptor.go @@ -3,7 +3,6 @@ package telegram import ( "context" "fmt" - "reflect" "strconv" "github.com/LightningTipBot/LightningTipBot/internal/errors" @@ -17,19 +16,10 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/lnbits" "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" -) - -type InterceptorType int - -const ( - MessageInterceptor InterceptorType = iota - CallbackInterceptor - QueryInterceptor + tb "gopkg.in/lightningtipbot/telebot.v3" ) type Interceptor struct { - Type InterceptorType Before []intercept.Func After []intercept.Func OnDefer []intercept.Func @@ -37,36 +27,35 @@ type Interceptor struct { // singletonClickInterceptor uses the onceMap to determine whether the object k1 already interacted // with the user k2. If so, it will return an error. -func (bot TipBot) singletonCallbackInterceptor(ctx context.Context, i interface{}) (context.Context, error) { - switch i.(type) { - case *tb.Callback: - c := i.(*tb.Callback) - return ctx, once.Once(c.Data, strconv.FormatInt(c.Sender.ID, 10)) +func (bot TipBot) singletonCallbackInterceptor(ctx intercept.Context) (intercept.Context, error) { + if ctx.Callback() != nil { + return ctx, once.Once(ctx.Callback().Data, strconv.FormatInt(ctx.Callback().Sender.ID, 10)) } return ctx, errors.Create(errors.InvalidTypeError) } // lockInterceptor invoked as first before interceptor -func (bot TipBot) lockInterceptor(ctx context.Context, i interface{}) (context.Context, error) { - user := getTelegramUserFromInterface(i) +func (bot TipBot) lockInterceptor(ctx intercept.Context) (intercept.Context, error) { + user := ctx.Sender() if user != nil { mutex.Lock(strconv.FormatInt(user.ID, 10)) return ctx, nil } - return nil, errors.Create(errors.InvalidTypeError) + return ctx, errors.Create(errors.InvalidTypeError) } // unlockInterceptor invoked as onDefer interceptor -func (bot TipBot) unlockInterceptor(ctx context.Context, i interface{}) (context.Context, error) { - user := getTelegramUserFromInterface(i) +func (bot TipBot) unlockInterceptor(ctx intercept.Context) (intercept.Context, error) { + user := ctx.Sender() if user != nil { mutex.Unlock(strconv.FormatInt(user.ID, 10)) return ctx, nil } return ctx, errors.Create(errors.InvalidTypeError) } -func (bot TipBot) idInterceptor(ctx context.Context, i interface{}) (context.Context, error) { - return context.WithValue(ctx, "uid", RandStringRunes(64)), nil +func (bot TipBot) idInterceptor(ctx intercept.Context) (intercept.Context, error) { + ctx.Context = context.WithValue(ctx, "uid", RandStringRunes(64)) + return ctx, nil } // answerCallbackInterceptor will answer the callback with the given text in the context @@ -92,30 +81,32 @@ func (bot TipBot) answerCallbackInterceptor(ctx context.Context, i interface{}) // requireUserInterceptor will return an error if user is not found // user is here an lnbits.User -func (bot TipBot) requireUserInterceptor(ctx context.Context, i interface{}) (context.Context, error) { +func (bot TipBot) requireUserInterceptor(ctx intercept.Context) (intercept.Context, error) { var user *lnbits.User var err error - u := getTelegramUserFromInterface(i) + u := ctx.Sender() if u != nil { user, err = GetUser(u, bot) // do not respond to banned users if bot.UserIsBanned(user) { - ctx = context.WithValue(ctx, "banned", true) - return context.WithValue(ctx, "user", user), errors.Create(errors.InvalidTypeError) + ctx.Context = context.WithValue(ctx, "banned", true) + ctx.Context = context.WithValue(ctx, "user", user) + return ctx, errors.Create(errors.InvalidTypeError) } if user != nil { - return context.WithValue(ctx, "user", user), err + ctx.Context = context.WithValue(ctx, "user", user) + return ctx, err } } - return nil, errors.Create(errors.InvalidTypeError) + return ctx, errors.Create(errors.InvalidTypeError) } // startUserInterceptor will invoke /start if user not exists. -func (bot TipBot) startUserInterceptor(ctx context.Context, i interface{}) (context.Context, error) { - ctx, err := bot.loadUserInterceptor(ctx, i) +func (bot TipBot) startUserInterceptor(ctx intercept.Context) (intercept.Context, error) { + handler, err := bot.loadUserInterceptor(ctx) if err != nil { // user banned - return ctx, err + return handler, err } // load user u := ctx.Value("user") @@ -124,49 +115,34 @@ func (bot TipBot) startUserInterceptor(ctx context.Context, i interface{}) (cont user := u.(*lnbits.User) // check wallet nil or !initialized if user.Wallet == nil || !user.Initialized { - ctx, err = bot.startHandler(ctx, i.(*tb.Message)) + handler, err = bot.startHandler(handler) if err != nil { - return ctx, err + return handler, err } - return ctx, nil + return handler, nil } } - return ctx, nil + return handler, nil } -func (bot TipBot) loadUserInterceptor(ctx context.Context, i interface{}) (context.Context, error) { - ctx, _ = bot.requireUserInterceptor(ctx, i) +func (bot TipBot) loadUserInterceptor(ctx intercept.Context) (intercept.Context, error) { + ctx, _ = bot.requireUserInterceptor(ctx) // if user is banned, also loadUserInterceptor will return an error if ctx.Value("banned") != nil && ctx.Value("banned").(bool) { - return nil, errors.Create(errors.InvalidTypeError) + return ctx, errors.Create(errors.InvalidTypeError) } return ctx, nil } -// getTelegramUserFromInterface returns the tb user based in interface type -func getTelegramUserFromInterface(i interface{}) (user *tb.User) { - switch i.(type) { - case *tb.Query: - user = &i.(*tb.Query).From - case *tb.Callback: - user = i.(*tb.Callback).Sender - case *tb.Message: - user = i.(*tb.Message).Sender - default: - log.Tracef("[getTelegramUserFromInterface] invalid type %s", reflect.TypeOf(i).String()) - } - return -} - // loadReplyToInterceptor Loading the Telegram user with message intercept -func (bot TipBot) loadReplyToInterceptor(ctx context.Context, i interface{}) (context.Context, error) { - switch i.(type) { - case *tb.Message: - m := i.(*tb.Message) - if m.ReplyTo != nil { - if m.ReplyTo.Sender != nil { - user, _ := GetUser(m.ReplyTo.Sender, bot) - user.Telegram = m.ReplyTo.Sender - return context.WithValue(ctx, "reply_to_user", user), nil +func (bot TipBot) loadReplyToInterceptor(ctx intercept.Context) (intercept.Context, error) { + if ctx.Message() != nil { + if ctx.Message().ReplyTo != nil { + if ctx.Message().ReplyTo.Sender != nil { + user, _ := GetUser(ctx.Message().ReplyTo.Sender, bot) + user.Telegram = ctx.Message().ReplyTo.Sender + ctx.Context = context.WithValue(ctx, "reply_to_user", user) + return ctx, nil + } } return ctx, nil @@ -174,75 +150,71 @@ func (bot TipBot) loadReplyToInterceptor(ctx context.Context, i interface{}) (co return ctx, errors.Create(errors.InvalidTypeError) } -func (bot TipBot) localizerInterceptor(ctx context.Context, i interface{}) (context.Context, error) { +func (bot TipBot) localizerInterceptor(ctx intercept.Context) (intercept.Context, error) { var userLocalizer *i18n2.Localizer var publicLocalizer *i18n2.Localizer // default language is english publicLocalizer = i18n2.NewLocalizer(i18n.Bundle, "en") - ctx = context.WithValue(ctx, "publicLanguageCode", "en") - ctx = context.WithValue(ctx, "publicLocalizer", publicLocalizer) + ctx.Context = context.WithValue(ctx, "publicLanguageCode", "en") + ctx.Context = context.WithValue(ctx, "publicLocalizer", publicLocalizer) - switch i.(type) { - case *tb.Message: - m := i.(*tb.Message) - userLocalizer = i18n2.NewLocalizer(i18n.Bundle, m.Sender.LanguageCode) - ctx = context.WithValue(ctx, "userLanguageCode", m.Sender.LanguageCode) - ctx = context.WithValue(ctx, "userLocalizer", userLocalizer) - if m.Private() { + if ctx.Message() != nil { + userLocalizer = i18n2.NewLocalizer(i18n.Bundle, ctx.Message().Sender.LanguageCode) + ctx.Context = context.WithValue(ctx, "userLanguageCode", ctx.Message().Sender.LanguageCode) + ctx.Context = context.WithValue(ctx, "userLocalizer", userLocalizer) + if ctx.Message().Private() { // in pm overwrite public localizer with user localizer - ctx = context.WithValue(ctx, "publicLanguageCode", m.Sender.LanguageCode) - ctx = context.WithValue(ctx, "publicLocalizer", userLocalizer) + ctx.Context = context.WithValue(ctx, "publicLanguageCode", ctx.Message().Sender.LanguageCode) + ctx.Context = context.WithValue(ctx, "publicLocalizer", userLocalizer) } return ctx, nil - case *tb.Callback: - m := i.(*tb.Callback) - userLocalizer = i18n2.NewLocalizer(i18n.Bundle, m.Sender.LanguageCode) - ctx = context.WithValue(ctx, "userLanguageCode", m.Sender.LanguageCode) - return context.WithValue(ctx, "userLocalizer", userLocalizer), nil - case *tb.Query: - m := i.(*tb.Query) - userLocalizer = i18n2.NewLocalizer(i18n.Bundle, m.From.LanguageCode) - ctx = context.WithValue(ctx, "userLanguageCode", m.From.LanguageCode) - return context.WithValue(ctx, "userLocalizer", userLocalizer), nil + } else if ctx.Callback() != nil { + userLocalizer = i18n2.NewLocalizer(i18n.Bundle, ctx.Callback().Sender.LanguageCode) + ctx.Context = context.WithValue(ctx, "userLanguageCode", ctx.Callback().Sender.LanguageCode) + ctx.Context = context.WithValue(ctx, "userLocalizer", userLocalizer) + return ctx, nil + } else if ctx.Query() != nil { + userLocalizer = i18n2.NewLocalizer(i18n.Bundle, ctx.Query().Sender.LanguageCode) + ctx.Context = context.WithValue(ctx, "userLanguageCode", ctx.Query().Sender.LanguageCode) + ctx.Context = context.WithValue(ctx, "userLocalizer", userLocalizer) + return ctx, nil } + return ctx, nil } -func (bot TipBot) requirePrivateChatInterceptor(ctx context.Context, i interface{}) (context.Context, error) { - switch i.(type) { - case *tb.Message: - m := i.(*tb.Message) - if m.Chat.Type != tb.ChatPrivate { - return nil, fmt.Errorf("[requirePrivateChatInterceptor] no private chat") +func (bot TipBot) requirePrivateChatInterceptor(ctx intercept.Context) (intercept.Context, error) { + if ctx.Message() != nil { + if ctx.Message().Chat.Type != tb.ChatPrivate { + return ctx, fmt.Errorf("[requirePrivateChatInterceptor] no private chat") } return ctx, nil } - return nil, errors.Create(errors.InvalidTypeError) + return ctx, errors.Create(errors.InvalidTypeError) } const photoTag = "" -func (bot TipBot) logMessageInterceptor(ctx context.Context, i interface{}) (context.Context, error) { - switch i.(type) { - case *tb.Message: - m := i.(*tb.Message) - if m.Text != "" { - log_string := fmt.Sprintf("[%s:%d %s:%d] %s", m.Chat.Title, m.Chat.ID, GetUserStr(m.Sender), m.Sender.ID, m.Text) - if m.IsReply() { - log_string = fmt.Sprintf("%s -> %s", log_string, GetUserStr(m.ReplyTo.Sender)) +func (bot TipBot) logMessageInterceptor(ctx intercept.Context) (intercept.Context, error) { + if ctx.Message() != nil { + + if ctx.Message().Text != "" { + log_string := fmt.Sprintf("[%s:%d %s:%d] %s", ctx.Message().Chat.Title, ctx.Message().Chat.ID, GetUserStr(ctx.Message().Sender), ctx.Message().Sender.ID, ctx.Message().Text) + if ctx.Message().IsReply() { + log_string = fmt.Sprintf("%s -> %s", log_string, GetUserStr(ctx.Message().ReplyTo.Sender)) } log.Infof(log_string) - } else if m.Photo != nil { - log.Infof("[%s:%d %s:%d] %s", m.Chat.Title, m.Chat.ID, GetUserStr(m.Sender), m.Sender.ID, photoTag) + } else if ctx.Message().Photo != nil { + log.Infof("[%s:%d %s:%d] %s", ctx.Message().Chat.Title, ctx.Message().Chat.ID, GetUserStr(ctx.Message().Sender), ctx.Message().Sender.ID, photoTag) } return ctx, nil - case *tb.Callback: - m := i.(*tb.Callback) - log.Infof("[Callback %s:%d] Data: %s", GetUserStr(m.Sender), m.Sender.ID, m.Data) + } else if ctx.Callback() != nil { + log.Infof("[Callback %s:%d] Data: %s", GetUserStr(ctx.Callback().Sender), ctx.Callback().Sender.ID, ctx.Callback().Data) return ctx, nil + } - return nil, errors.Create(errors.InvalidTypeError) + return ctx, errors.Create(errors.InvalidTypeError) } // LoadUser from context diff --git a/internal/telegram/invoice.go b/internal/telegram/invoice.go index 28e72c1..77a79bd 100644 --- a/internal/telegram/invoice.go +++ b/internal/telegram/invoice.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "strings" "time" @@ -19,7 +20,7 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/runtime" "github.com/LightningTipBot/LightningTipBot/internal/str" "github.com/skip2/go-qrcode" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) type InvoiceEventCallback map[int]EventHandler @@ -102,9 +103,10 @@ func helpInvoiceUsage(ctx context.Context, errormsg string) string { } } -func (bot *TipBot) invoiceHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) invoiceHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() // check and print all commands - bot.anyTextHandler(ctx, m) + bot.anyTextHandler(ctx) user := LoadUser(ctx) if user.Wallet == nil { return ctx, errors.Create(errors.UserNoWalletError) diff --git a/internal/telegram/link.go b/internal/telegram/link.go index 4647a72..0f6647f 100644 --- a/internal/telegram/link.go +++ b/internal/telegram/link.go @@ -2,24 +2,25 @@ package telegram import ( "bytes" - "context" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "time" "github.com/LightningTipBot/LightningTipBot/internal" log "github.com/sirupsen/logrus" "github.com/skip2/go-qrcode" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) -func (bot *TipBot) lndhubHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) lndhubHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() if internal.Configuration.Lnbits.LnbitsPublicUrl == "" { bot.trySendMessage(m.Sender, Translate(ctx, "couldNotLinkMessage")) return ctx, fmt.Errorf("invalid configuration") } // check and print all commands - bot.anyTextHandler(ctx, m) + bot.anyTextHandler(ctx) // reply only in private message if m.Chat.Type != tb.ChatPrivate { // delete message diff --git a/internal/telegram/lnurl-auth.go b/internal/telegram/lnurl-auth.go index 30422cb..2f408a6 100644 --- a/internal/telegram/lnurl-auth.go +++ b/internal/telegram/lnurl-auth.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "net/url" "github.com/LightningTipBot/LightningTipBot/internal/errors" @@ -17,11 +18,11 @@ import ( lnurl "github.com/fiatjaf/go-lnurl" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) var ( - authConfirmationMenu = &tb.ReplyMarkup{ResizeReplyKeyboard: true} + authConfirmationMenu = &tb.ReplyMarkup{ResizeKeyboard: true} btnCancelAuth = paymentConfirmationMenu.Data("đŸšĢ Cancel", "cancel_login") btnAuth = paymentConfirmationMenu.Data("✅ Login", "confirm_login") ) @@ -69,7 +70,8 @@ func (bot *TipBot) lnurlAuthHandler(ctx context.Context, m *tb.Message, authPara return ctx, nil } -func (bot *TipBot) confirmLnurlAuthHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) confirmLnurlAuthHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() tx := &LnurlAuthState{Base: storage.New(storage.ID(c.Data))} mutex.LockWithContext(ctx, tx.ID) defer mutex.UnlockWithContext(ctx, tx.ID) @@ -118,7 +120,7 @@ func (bot *TipBot) confirmLnurlAuthHandler(ctx context.Context, c *tb.Callback) return ctx, err } if sentsigres.Status == "ERROR" { - bot.tryEditMessage(c.Message, fmt.Sprintf(Translate(ctx, "errorReasonMessage"), sentsigres.Reason)) + bot.tryEditMessage(c, fmt.Sprintf(Translate(ctx, "errorReasonMessage"), sentsigres.Reason)) return ctx, err } bot.editSingleButton(ctx, c.Message, lnurlAuthState.Message.Text, Translate(ctx, "lnurlSuccessfulLogin")) @@ -126,7 +128,8 @@ func (bot *TipBot) confirmLnurlAuthHandler(ctx context.Context, c *tb.Callback) } // cancelPaymentHandler invoked when user clicked cancel on payment confirmation -func (bot *TipBot) cancelLnurlAuthHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) cancelLnurlAuthHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() tx := &LnurlAuthState{Base: storage.New(storage.ID(c.Data))} mutex.LockWithContext(ctx, tx.ID) defer mutex.UnlockWithContext(ctx, tx.ID) @@ -143,7 +146,7 @@ func (bot *TipBot) cancelLnurlAuthHandler(ctx context.Context, c *tb.Callback) ( return ctx, errors.Create(errors.UnknownError) } // delete and send instead of edit for the keyboard to pop up after sending - bot.tryEditMessage(c.Message, i18n.Translate(lnurlAuthState.LanguageCode, "loginCancelledMessage"), &tb.ReplyMarkup{}) + bot.tryEditMessage(c, i18n.Translate(lnurlAuthState.LanguageCode, "loginCancelledMessage"), &tb.ReplyMarkup{}) // bot.tryEditMessage(c.Message, i18n.Translate(payData.LanguageCode, "paymentCancelledMessage"), &tb.ReplyMarkup{}) return ctx, lnurlAuthState.Inactivate(lnurlAuthState, bot.Bunt) } diff --git a/internal/telegram/lnurl-pay.go b/internal/telegram/lnurl-pay.go index f85e4ca..2c78cd9 100644 --- a/internal/telegram/lnurl-pay.go +++ b/internal/telegram/lnurl-pay.go @@ -1,9 +1,9 @@ package telegram import ( - "context" "encoding/json" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "io/ioutil" "net/url" "strconv" @@ -18,7 +18,6 @@ import ( lnurl "github.com/fiatjaf/go-lnurl" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" ) // LnurlPayState saves the state of the user for an LNURL payment @@ -34,7 +33,8 @@ type LnurlPayState struct { // lnurlPayHandler1 is invoked when the first lnurl response was a lnurlpay response // at this point, the user hans't necessarily entered an amount yet -func (bot *TipBot) lnurlPayHandler(ctx context.Context, m *tb.Message, payParams *LnurlPayState) { +func (bot *TipBot) lnurlPayHandler(ctx intercept.Context, payParams *LnurlPayState) { + m := ctx.Message() user := LoadUser(ctx) if user.Wallet == nil { return @@ -92,7 +92,7 @@ func (bot *TipBot) lnurlPayHandler(ctx context.Context, m *tb.Message, payParams return } - // We need to save the pay state in the user state so we can load the payment in the next handler + // We need to save the pay state in the user state so we can load the payment in the next ctx paramsJson, err := json.Marshal(payParams) if err != nil { log.Errorf("[lnurlPayHandler] Error: %s", err.Error()) @@ -101,12 +101,13 @@ func (bot *TipBot) lnurlPayHandler(ctx context.Context, m *tb.Message, payParams } SetUserState(user, bot, lnbits.UserHasEnteredAmount, string(paramsJson)) // directly go to confirm - bot.lnurlPayHandlerSend(ctx, m) + bot.lnurlPayHandlerSend(ctx) return } // lnurlPayHandlerSend is invoked when the user has delivered an amount and is ready to pay -func (bot *TipBot) lnurlPayHandlerSend(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) lnurlPayHandlerSend(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() user := LoadUser(ctx) if user.Wallet == nil { return ctx, errors.Create(errors.UserNoWalletError) @@ -194,10 +195,11 @@ func (bot *TipBot) lnurlPayHandlerSend(ctx context.Context, m *tb.Message) (cont runtime.IgnoreError(lnurlPayState.Set(lnurlPayState, bot.Bunt)) bot.Telegram.Delete(statusMsg) m.Text = fmt.Sprintf("/pay %s", response2.PR) - return bot.payHandler(ctx, m) + return bot.payHandler(ctx) } -func (bot *TipBot) sendToLightningAddress(ctx context.Context, m *tb.Message, address string, amount int64) (context.Context, error) { +func (bot *TipBot) sendToLightningAddress(ctx intercept.Context, address string, amount int64) (intercept.Context, error) { + m := ctx.Message() split := strings.Split(address, "@") if len(split) != 2 { return ctx, fmt.Errorf("lightning address format wrong") @@ -232,6 +234,5 @@ func (bot *TipBot) sendToLightningAddress(ctx context.Context, m *tb.Message, ad // this will invoke the "enter amount" dialog in the lnurl handler m.Text = fmt.Sprintf("/lnurl %s", lnurl) } - bot.lnurlHandler(ctx, m) - return ctx, nil + return bot.lnurlHandler(ctx) } diff --git a/internal/telegram/lnurl-withdraw.go b/internal/telegram/lnurl-withdraw.go index 3bc5e96..6c5f31e 100644 --- a/internal/telegram/lnurl-withdraw.go +++ b/internal/telegram/lnurl-withdraw.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "io/ioutil" "net/url" @@ -20,11 +21,11 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/str" lnurl "github.com/fiatjaf/go-lnurl" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) var ( - withdrawConfirmationMenu = &tb.ReplyMarkup{ResizeReplyKeyboard: true} + withdrawConfirmationMenu = &tb.ReplyMarkup{ResizeKeyboard: true} btnCancelWithdraw = paymentConfirmationMenu.Data("đŸšĢ Cancel", "cancel_withdraw") btnWithdraw = paymentConfirmationMenu.Data("✅ Withdraw", "confirm_withdraw") ) @@ -58,7 +59,8 @@ func (bot *TipBot) editSingleButton(ctx context.Context, m *tb.Message, message // lnurlWithdrawHandler is invoked when the first lnurl response was a lnurl-withdraw response // at this point, the user hans't necessarily entered an amount yet -func (bot *TipBot) lnurlWithdrawHandler(ctx context.Context, m *tb.Message, withdrawParams *LnurlWithdrawState) { +func (bot *TipBot) lnurlWithdrawHandler(ctx intercept.Context, withdrawParams *LnurlWithdrawState) { + m := ctx.Message() user := LoadUser(ctx) if user.Wallet == nil { return @@ -104,7 +106,7 @@ func (bot *TipBot) lnurlWithdrawHandler(ctx context.Context, m *tb.Message, with return } - // We need to save the pay state in the user state so we can load the payment in the next handler + // We need to save the pay state in the user state so we can load the payment in the next ctx paramsJson, err := json.Marshal(withdrawParams) if err != nil { log.Errorf("[lnurlWithdrawHandler] Error: %s", err.Error()) @@ -113,12 +115,13 @@ func (bot *TipBot) lnurlWithdrawHandler(ctx context.Context, m *tb.Message, with } SetUserState(user, bot, lnbits.UserHasEnteredAmount, string(paramsJson)) // directly go to confirm - bot.lnurlWithdrawHandlerWithdraw(ctx, m) + bot.lnurlWithdrawHandlerWithdraw(ctx) return } // lnurlWithdrawHandlerWithdraw is invoked when the user has delivered an amount and is ready to pay -func (bot *TipBot) lnurlWithdrawHandlerWithdraw(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) lnurlWithdrawHandlerWithdraw(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() user := LoadUser(ctx) if user.Wallet == nil { return ctx, errors.Create(errors.UserNoWalletError) @@ -186,7 +189,8 @@ func (bot *TipBot) lnurlWithdrawHandlerWithdraw(ctx context.Context, m *tb.Messa } // confirmPayHandler when user clicked pay on payment confirmation -func (bot *TipBot) confirmWithdrawHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) confirmWithdrawHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() tx := &LnurlWithdrawState{Base: storage.New(storage.ID(c.Data))} mutex.LockWithContext(ctx, tx.ID) defer mutex.UnlockWithContext(ctx, tx.ID) @@ -210,15 +214,15 @@ func (bot *TipBot) confirmWithdrawHandler(ctx context.Context, c *tb.Callback) ( } if !lnurlWithdrawState.Active { log.Errorf("[confirmPayHandler] send not active anymore") - bot.tryEditMessage(c.Message, i18n.Translate(lnurlWithdrawState.LanguageCode, "errorTryLaterMessage"), &tb.ReplyMarkup{}) - bot.tryDeleteMessage(c.Message) + bot.tryEditMessage(c, i18n.Translate(lnurlWithdrawState.LanguageCode, "errorTryLaterMessage"), &tb.ReplyMarkup{}) + bot.tryDeleteMessage(c) return ctx, errors.Create(errors.NotActiveError) } defer lnurlWithdrawState.Set(lnurlWithdrawState, bot.Bunt) user := LoadUser(ctx) if user.Wallet == nil { - bot.tryDeleteMessage(c.Message) + bot.tryDeleteMessage(c) return ctx, errors.Create(errors.UserNoWalletError) } @@ -231,7 +235,7 @@ func (bot *TipBot) confirmWithdrawHandler(ctx context.Context, c *tb.Callback) ( callbackUrl, err := url.Parse(lnurlWithdrawState.LNURLWithdrawResponse.Callback) if err != nil { log.Errorf("[lnurlWithdrawHandlerWithdraw] Error: %s", err.Error()) - // bot.trySendMessage(c.Sender, Translate(ctx, "errorTryLaterMessage")) + // bot.trySendMessage(c.Sender, Translate(handler.Ctx, "errorTryLaterMessage")) bot.editSingleButton(ctx, c.Message, lnurlWithdrawState.Message, i18n.Translate(lnurlWithdrawState.LanguageCode, "errorTryLaterMessage")) return ctx, err } @@ -270,14 +274,14 @@ func (bot *TipBot) confirmWithdrawHandler(ctx context.Context, c *tb.Callback) ( res, err := client.Get(callbackUrl.String()) if err != nil || res.StatusCode >= 300 { log.Errorf("[lnurlWithdrawHandlerWithdraw] Failed.") - // bot.trySendMessage(c.Sender, Translate(ctx, "errorTryLaterMessage")) + // bot.trySendMessage(c.Sender, Translate(handler.Ctx, "errorTryLaterMessage")) bot.editSingleButton(ctx, c.Message, lnurlWithdrawState.Message, i18n.Translate(lnurlWithdrawState.LanguageCode, "errorTryLaterMessage")) return ctx, errors.New(errors.UnknownError, err) } body, err := ioutil.ReadAll(res.Body) if err != nil { log.Errorf("[lnurlWithdrawHandlerWithdraw] Error: %s", err.Error()) - // bot.trySendMessage(c.Sender, Translate(ctx, "errorTryLaterMessage")) + // bot.trySendMessage(c.Sender, Translate(handler.Ctx, "errorTryLaterMessage")) bot.editSingleButton(ctx, c.Message, lnurlWithdrawState.Message, i18n.Translate(lnurlWithdrawState.LanguageCode, "errorTryLaterMessage")) return ctx, err } @@ -303,7 +307,8 @@ func (bot *TipBot) confirmWithdrawHandler(ctx context.Context, c *tb.Callback) ( } // cancelPaymentHandler invoked when user clicked cancel on payment confirmation -func (bot *TipBot) cancelWithdrawHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) cancelWithdrawHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() // reset state immediately user := LoadUser(ctx) ResetUserState(user, bot) @@ -326,6 +331,6 @@ func (bot *TipBot) cancelWithdrawHandler(ctx context.Context, c *tb.Callback) (c if lnurlWithdrawState.From.Telegram.ID != c.Sender.ID { return ctx, errors.Create(errors.UnknownError) } - bot.tryEditMessage(c.Message, i18n.Translate(lnurlWithdrawState.LanguageCode, "lnurlWithdrawCancelled"), &tb.ReplyMarkup{}) + bot.tryEditMessage(c, i18n.Translate(lnurlWithdrawState.LanguageCode, "lnurlWithdrawCancelled"), &tb.ReplyMarkup{}) return ctx, lnurlWithdrawState.Inactivate(lnurlWithdrawState, bot.Bunt) } diff --git a/internal/telegram/lnurl.go b/internal/telegram/lnurl.go index 15069b8..8b0bb37 100644 --- a/internal/telegram/lnurl.go +++ b/internal/telegram/lnurl.go @@ -2,8 +2,8 @@ package telegram import ( "bytes" - "context" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "io/ioutil" "net/http" "net/url" @@ -18,7 +18,7 @@ import ( lnurl "github.com/fiatjaf/go-lnurl" log "github.com/sirupsen/logrus" "github.com/skip2/go-qrcode" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) func (bot *TipBot) GetHttpClient() (*http.Client, error) { @@ -37,11 +37,12 @@ func (bot TipBot) cancelLnUrlHandler(c *tb.Callback) { } // lnurlHandler is invoked on /lnurl command -func (bot *TipBot) lnurlHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) lnurlHandler(ctx intercept.Context) (intercept.Context, error) { // commands: // /lnurl // /lnurl // or /lnurl + m := ctx.Message() if m.Chat.Type != tb.ChatPrivate { return ctx, errors.Create(errors.NoPrivateChatError) } @@ -53,7 +54,7 @@ func (bot *TipBot) lnurlHandler(ctx context.Context, m *tb.Message) (context.Con // if only /lnurl is entered, show the lnurl of the user if m.Text == "/lnurl" { - return bot.lnurlReceiveHandler(ctx, m) + return bot.lnurlReceiveHandler(ctx) } statusMsg := bot.trySendMessageEditable(m.Sender, Translate(ctx, "lnurlResolvingUrlMessage")) @@ -89,7 +90,8 @@ func (bot *TipBot) lnurlHandler(ctx context.Context, m *tb.Message) (context.Con authParams := &LnurlAuthState{LNURLAuthParams: params.(lnurl.LNURLAuthParams)} log.Infof("[LNURL-auth] %s", authParams.LNURLAuthParams.Callback) bot.tryDeleteMessage(statusMsg) - return bot.lnurlAuthHandler(ctx, m, authParams) + ctx.Context, err = bot.lnurlAuthHandler(ctx, m, authParams) + return ctx, err case lnurl.LNURLPayParams: payParams := &LnurlPayState{LNURLPayParams: params.(lnurl.LNURLPayParams)} @@ -107,13 +109,13 @@ func (bot *TipBot) lnurlHandler(ctx context.Context, m *tb.Message) (context.Con bot.trySendMessage(m.Sender, fmt.Sprintf("`%s`", payParams.LNURLPayParams.Metadata.Description)) } // ask whether to make payment - bot.lnurlPayHandler(ctx, m, payParams) + bot.lnurlPayHandler(ctx, payParams) case lnurl.LNURLWithdrawResponse: withdrawParams := &LnurlWithdrawState{LNURLWithdrawResponse: params.(lnurl.LNURLWithdrawResponse)} log.Infof("[LNURL-w] %s", withdrawParams.LNURLWithdrawResponse.Callback) bot.tryDeleteMessage(statusMsg) - bot.lnurlWithdrawHandler(ctx, m, withdrawParams) + bot.lnurlWithdrawHandler(ctx, withdrawParams) default: if err == nil { err = fmt.Errorf("invalid LNURL type") @@ -152,7 +154,8 @@ func UserGetLNURL(user *lnbits.User) (string, error) { } // lnurlReceiveHandler outputs the LNURL of the user -func (bot TipBot) lnurlReceiveHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot TipBot) lnurlReceiveHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() fromUser := LoadUser(ctx) lnurlEncode, err := UserGetLNURL(fromUser) if err != nil { diff --git a/internal/telegram/message.go b/internal/telegram/message.go index b1341ce..fac16bc 100644 --- a/internal/telegram/message.go +++ b/internal/telegram/message.go @@ -4,7 +4,7 @@ import ( "strconv" "time" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) type Message struct { diff --git a/internal/telegram/pay.go b/internal/telegram/pay.go index 92af919..0cc4dd1 100644 --- a/internal/telegram/pay.go +++ b/internal/telegram/pay.go @@ -3,6 +3,7 @@ package telegram import ( "context" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "strings" "github.com/LightningTipBot/LightningTipBot/internal/errors" @@ -17,11 +18,11 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/str" decodepay "github.com/fiatjaf/ln-decodepay" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) var ( - paymentConfirmationMenu = &tb.ReplyMarkup{ResizeReplyKeyboard: true} + paymentConfirmationMenu = &tb.ReplyMarkup{ResizeKeyboard: true} btnCancelPay = paymentConfirmationMenu.Data("đŸšĢ Cancel", "cancel_pay") btnPay = paymentConfirmationMenu.Data("✅ Pay", "confirm_pay") ) @@ -48,23 +49,23 @@ type PayData struct { } // payHandler invoked on "/pay lnbc..." command -func (bot *TipBot) payHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) payHandler(ctx intercept.Context) (intercept.Context, error) { // check and print all commands - bot.anyTextHandler(ctx, m) + bot.anyTextHandler(ctx) user := LoadUser(ctx) if user.Wallet == nil { return ctx, errors.Create(errors.UserNoWalletError) } - if len(strings.Split(m.Text, " ")) < 2 { - NewMessage(m, WithDuration(0, bot)) - bot.trySendMessage(m.Sender, helpPayInvoiceUsage(ctx, "")) + if len(strings.Split(ctx.Message().Text, " ")) < 2 { + NewMessage(ctx.Message(), WithDuration(0, bot)) + bot.trySendMessage(ctx.Sender(), helpPayInvoiceUsage(ctx, "")) return ctx, errors.Create(errors.InvalidSyntaxError) } - userStr := GetUserStr(m.Sender) - paymentRequest, err := getArgumentFromCommand(m.Text, 1) + userStr := GetUserStr(ctx.Sender()) + paymentRequest, err := getArgumentFromCommand(ctx.Message().Text, 1) if err != nil { - NewMessage(m, WithDuration(0, bot)) - bot.trySendMessage(m.Sender, helpPayInvoiceUsage(ctx, Translate(ctx, "invalidInvoiceHelpMessage"))) + NewMessage(ctx.Message(), WithDuration(0, bot)) + bot.trySendMessage(ctx.Sender(), helpPayInvoiceUsage(ctx, Translate(ctx, "invalidInvoiceHelpMessage"))) errmsg := fmt.Sprintf("[/pay] Error: Could not getArgumentFromCommand: %s", err.Error()) log.Errorln(errmsg) return ctx, errors.New(errors.InvalidSyntaxError, err) @@ -76,7 +77,7 @@ func (bot *TipBot) payHandler(ctx context.Context, m *tb.Message) (context.Conte // decode invoice bolt11, err := decodepay.Decodepay(paymentRequest) if err != nil { - bot.trySendMessage(m.Sender, helpPayInvoiceUsage(ctx, Translate(ctx, "invalidInvoiceHelpMessage"))) + bot.trySendMessage(ctx.Sender(), helpPayInvoiceUsage(ctx, Translate(ctx, "invalidInvoiceHelpMessage"))) errmsg := fmt.Sprintf("[/pay] Error: Could not decode invoice: %s", err.Error()) log.Errorln(errmsg) return ctx, errors.New(errors.InvalidSyntaxError, err) @@ -84,7 +85,7 @@ func (bot *TipBot) payHandler(ctx context.Context, m *tb.Message) (context.Conte amount := int64(bolt11.MSatoshi / 1000) if amount <= 0 { - bot.trySendMessage(m.Sender, Translate(ctx, "invoiceNoAmountMessage")) + bot.trySendMessage(ctx.Sender(), Translate(ctx, "invoiceNoAmountMessage")) errmsg := fmt.Sprint("[/pay] Error: invoice without amount") log.Warnln(errmsg) return ctx, errors.Create(errors.InvalidAmountError) @@ -93,21 +94,21 @@ func (bot *TipBot) payHandler(ctx context.Context, m *tb.Message) (context.Conte // check user balance first balance, err := bot.GetUserBalance(user) if err != nil { - NewMessage(m, WithDuration(0, bot)) + NewMessage(ctx.Message(), WithDuration(0, bot)) errmsg := fmt.Sprintf("[/pay] Error: Could not get user balance: %s", err.Error()) log.Errorln(errmsg) - bot.trySendMessage(m.Sender, Translate(ctx, "errorTryLaterMessage")) + bot.trySendMessage(ctx.Sender(), Translate(ctx, "errorTryLaterMessage")) return ctx, errors.New(errors.GetBalanceError, err) } if amount > balance { - NewMessage(m, WithDuration(0, bot)) - bot.trySendMessage(m.Sender, fmt.Sprintf(Translate(ctx, "insufficientFundsMessage"), balance, amount)) + NewMessage(ctx.Message(), WithDuration(0, bot)) + bot.trySendMessage(ctx.Sender(), fmt.Sprintf(Translate(ctx, "insufficientFundsMessage"), balance, amount)) return ctx, errors.Create(errors.InvalidSyntaxError) } // send warning that the invoice might fail due to missing fee reserve if float64(amount) > float64(balance)*0.98 { - bot.trySendMessage(m.Sender, Translate(ctx, "feeReserveMessage")) + bot.trySendMessage(ctx.Sender(), Translate(ctx, "feeReserveMessage")) } confirmText := fmt.Sprintf(Translate(ctx, "confirmPayInvoiceMessage"), amount) @@ -118,7 +119,7 @@ func (bot *TipBot) payHandler(ctx context.Context, m *tb.Message) (context.Conte log.Infof("[/pay] Invoice entered. User: %s, amount: %d sat.", userStr, amount) // object that holds all information about the send payment - id := fmt.Sprintf("pay:%d-%d-%s", m.Sender.ID, amount, RandStringRunes(5)) + id := fmt.Sprintf("pay:%d-%d-%s", ctx.Sender().ID, amount, RandStringRunes(5)) // // // create inline buttons payButton := paymentConfirmationMenu.Data(Translate(ctx, "payButtonMessage"), "confirm_pay", id) @@ -129,7 +130,7 @@ func (bot *TipBot) payHandler(ctx context.Context, m *tb.Message) (context.Conte payButton, cancelButton), ) - payMessage := bot.trySendMessageEditable(m.Chat, confirmText, paymentConfirmationMenu) + payMessage := bot.trySendMessageEditable(ctx.Chat(), confirmText, paymentConfirmationMenu) payData := &PayData{ Base: storage.New(storage.ID(id)), From: user, @@ -148,8 +149,8 @@ func (bot *TipBot) payHandler(ctx context.Context, m *tb.Message) (context.Conte } // confirmPayHandler when user clicked pay on payment confirmation -func (bot *TipBot) confirmPayHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { - tx := &PayData{Base: storage.New(storage.ID(c.Data))} +func (bot *TipBot) confirmPayHandler(ctx intercept.Context) (intercept.Context, error) { + tx := &PayData{Base: storage.New(storage.ID(ctx.Data()))} mutex.LockWithContext(ctx, tx.ID) defer mutex.UnlockWithContext(ctx, tx.ID) sn, err := tx.Get(tx, bot.Bunt) @@ -161,23 +162,23 @@ func (bot *TipBot) confirmPayHandler(ctx context.Context, c *tb.Callback) (conte payData := sn.(*PayData) // onnly the correct user can press - if payData.From.Telegram.ID != c.Sender.ID { + if payData.From.Telegram.ID != ctx.Sender().ID { return ctx, errors.Create(errors.UnknownError) } if !payData.Active { log.Errorf("[confirmPayHandler] send not active anymore") - bot.tryEditMessage(c.Message, i18n.Translate(payData.LanguageCode, "errorTryLaterMessage"), &tb.ReplyMarkup{}) - bot.tryDeleteMessage(c.Message) + bot.tryEditMessage(ctx.Message(), i18n.Translate(payData.LanguageCode, "errorTryLaterMessage"), &tb.ReplyMarkup{}) + bot.tryDeleteMessage(ctx.Message()) return ctx, errors.Create(errors.NotActiveError) } defer payData.Set(payData, bot.Bunt) // remove buttons from confirmation message - // bot.tryEditMessage(c.Message, MarkdownEscape(payData.Message), &tb.ReplyMarkup{}) + // bot.tryEditMessage(handler.Message(), MarkdownEscape(payData.Message), &tb.ReplyMarkup{}) user := LoadUser(ctx) if user.Wallet == nil { - bot.tryDeleteMessage(c.Message) + bot.tryDeleteMessage(ctx.Message()) return ctx, errors.Create(errors.UserNoWalletError) } @@ -186,11 +187,11 @@ func (bot *TipBot) confirmPayHandler(ctx context.Context, c *tb.Callback) (conte // reset state immediately ResetUserState(user, bot) - userStr := GetUserStr(c.Sender) + userStr := GetUserStr(ctx.Sender()) // update button text bot.tryEditMessage( - c.Message, + ctx.Message(), payData.Message, &tb.ReplyMarkup{ InlineKeyboard: [][]tb.InlineButton{ @@ -205,7 +206,7 @@ func (bot *TipBot) confirmPayHandler(ctx context.Context, c *tb.Callback) (conte if err != nil { errmsg := fmt.Sprintf("[/pay] Could not pay invoice of %s: %s", userStr, err) err = fmt.Errorf(i18n.Translate(payData.LanguageCode, "invoiceUndefinedErrorMessage")) - bot.tryEditMessage(c.Message, fmt.Sprintf(i18n.Translate(payData.LanguageCode, "invoicePaymentFailedMessage"), err.Error()), &tb.ReplyMarkup{}) + bot.tryEditMessage(ctx.Message(), fmt.Sprintf(i18n.Translate(payData.LanguageCode, "invoicePaymentFailedMessage"), err.Error()), &tb.ReplyMarkup{}) // verbose error message, turned off for now // if len(err.Error()) == 0 { // err = fmt.Errorf(i18n.Translate(payData.LanguageCode, "invoiceUndefinedErrorMessage")) @@ -223,27 +224,27 @@ func (bot *TipBot) confirmPayHandler(ctx context.Context, c *tb.Callback) (conte log.Errorln(errmsg) } - if c.Message.Private() { + if ctx.Message().Private() { // if the command was invoked in private chat // the edit below was cool, but we need to pop up the keyboard again // bot.tryEditMessage(c.Message, i18n.Translate(payData.LanguageCode, "invoicePaidMessage"), &tb.ReplyMarkup{}) - bot.tryDeleteMessage(c.Message) - bot.trySendMessage(c.Sender, i18n.Translate(payData.LanguageCode, "invoicePaidMessage")) + bot.tryDeleteMessage(ctx.Message()) + bot.trySendMessage(ctx.Sender(), i18n.Translate(payData.LanguageCode, "invoicePaidMessage")) } else { // if the command was invoked in group chat - bot.trySendMessage(c.Sender, i18n.Translate(payData.LanguageCode, "invoicePaidMessage")) - bot.tryEditMessage(c.Message, fmt.Sprintf(i18n.Translate(payData.LanguageCode, "invoicePublicPaidMessage"), userStr), &tb.ReplyMarkup{}) + bot.trySendMessage(ctx.Sender(), i18n.Translate(payData.LanguageCode, "invoicePaidMessage")) + bot.tryEditMessage(ctx.Message(), fmt.Sprintf(i18n.Translate(payData.LanguageCode, "invoicePublicPaidMessage"), userStr), &tb.ReplyMarkup{}) } log.Infof("[âšĄī¸ pay] User %s paid invoice %s (%d sat)", userStr, payData.ID, payData.Amount) return ctx, nil } // cancelPaymentHandler invoked when user clicked cancel on payment confirmation -func (bot *TipBot) cancelPaymentHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) cancelPaymentHandler(ctx intercept.Context) (intercept.Context, error) { // reset state immediately user := LoadUser(ctx) ResetUserState(user, bot) - tx := &PayData{Base: storage.New(storage.ID(c.Data))} + tx := &PayData{Base: storage.New(storage.ID(ctx.Data()))} mutex.LockWithContext(ctx, tx.ID) defer mutex.UnlockWithContext(ctx, tx.ID) // immediatelly set intransaction to block duplicate calls @@ -254,12 +255,12 @@ func (bot *TipBot) cancelPaymentHandler(ctx context.Context, c *tb.Callback) (co } payData := sn.(*PayData) // onnly the correct user can press - if payData.From.Telegram.ID != c.Sender.ID { + if payData.From.Telegram.ID != ctx.Callback().Sender.ID { return ctx, errors.Create(errors.UnknownError) } // delete and send instead of edit for the keyboard to pop up after sending - bot.tryDeleteMessage(c.Message) - bot.trySendMessage(c.Message.Chat, i18n.Translate(payData.LanguageCode, "paymentCancelledMessage")) + bot.tryDeleteMessage(ctx.Message()) + bot.trySendMessage(ctx.Message().Chat, i18n.Translate(payData.LanguageCode, "paymentCancelledMessage")) // bot.tryEditMessage(c.Message, i18n.Translate(payData.LanguageCode, "paymentCancelledMessage"), &tb.ReplyMarkup{}) return ctx, payData.Inactivate(payData, bot.Bunt) diff --git a/internal/telegram/photo.go b/internal/telegram/photo.go index b35b409..fd91475 100644 --- a/internal/telegram/photo.go +++ b/internal/telegram/photo.go @@ -2,9 +2,9 @@ package telegram import ( "bytes" - "context" "encoding/json" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "image" "image/jpeg" "strings" @@ -17,10 +17,10 @@ import ( "github.com/nfnt/resize" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) -// TryRecognizeInvoiceFromQrCode will try to read an invoice string from a qr code and invoke the payment handler. +// TryRecognizeInvoiceFromQrCode will try to read an invoice string from a qr code and invoke the payment ctx. func TryRecognizeQrCode(img image.Image) (*gozxing.Result, error) { // check for qr code bmp, _ := gozxing.NewBinaryBitmapFromImage(img) @@ -33,14 +33,15 @@ func TryRecognizeQrCode(img image.Image) (*gozxing.Result, error) { payload := strings.ToLower(result.String()) if lightning.IsInvoice(payload) || lightning.IsLnurl(payload) { // create payment command payload - // invoke payment confirmation handler + // invoke payment confirmation ctx return result, nil } return nil, fmt.Errorf("no codes found") } // photoHandler is the handler function for every photo from a private chat that the bot receives -func (bot *TipBot) photoHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) photoHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() if m.Chat.Type != tb.ChatPrivate { return ctx, errors.Create(errors.NoPrivateChatError) } @@ -49,13 +50,13 @@ func (bot *TipBot) photoHandler(ctx context.Context, m *tb.Message) (context.Con } user := LoadUser(ctx) if c := stateCallbackMessage[user.StateKey]; c != nil { - ctx, err := c(ctx, m) + ctx, err := c(ctx) ResetUserState(user, bot) return ctx, err } // get file reader closer from Telegram api - reader, err := bot.Telegram.GetFile(m.Photo.MediaFile()) + reader, err := bot.Telegram.File(m.Photo.MediaFile()) if err != nil { log.Errorf("[photoHandler] getfile error: %v\n", err.Error()) return ctx, err @@ -77,10 +78,10 @@ func (bot *TipBot) photoHandler(ctx context.Context, m *tb.Message) (context.Con // invoke payment handler if lightning.IsInvoice(data.String()) { m.Text = fmt.Sprintf("/pay %s", data.String()) - return bot.payHandler(ctx, m) + return bot.payHandler(ctx) } else if lightning.IsLnurl(data.String()) { m.Text = fmt.Sprintf("/lnurl %s", data.String()) - return bot.lnurlHandler(ctx, m) + return bot.lnurlHandler(ctx) } return ctx, nil } @@ -98,7 +99,7 @@ func DownloadProfilePicture(telegram *tb.Bot, user *tb.User) ([]byte, error) { return nil, err } buf := new(bytes.Buffer) - reader, err := telegram.GetFile(&photo[0].File) + reader, err := telegram.File(&photo[0].File) if err != nil { log.Errorf("[DownloadProfilePicture] %v", err) return nil, err diff --git a/internal/telegram/send.go b/internal/telegram/send.go index 695d258..63bf3e4 100644 --- a/internal/telegram/send.go +++ b/internal/telegram/send.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "strings" "github.com/LightningTipBot/LightningTipBot/internal/errors" @@ -18,11 +19,11 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/str" "github.com/LightningTipBot/LightningTipBot/pkg/lightning" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) var ( - sendConfirmationMenu = &tb.ReplyMarkup{ResizeReplyKeyboard: true} + sendConfirmationMenu = &tb.ReplyMarkup{ResizeKeyboard: true} btnCancelSend = sendConfirmationMenu.Data("đŸšĢ Cancel", "cancel_send") btnSend = sendConfirmationMenu.Data("✅ Send", "confirm_send") ) @@ -55,8 +56,8 @@ type SendData struct { } // sendHandler invoked on "/send 123 @user" command -func (bot *TipBot) sendHandler(ctx context.Context, m *tb.Message) (context.Context, error) { - bot.anyTextHandler(ctx, m) +func (bot *TipBot) sendHandler(ctx intercept.Context) (intercept.Context, error) { + bot.anyTextHandler(ctx) user := LoadUser(ctx) if user.Wallet == nil { return ctx, errors.Create(errors.UserNoWalletError) @@ -68,8 +69,8 @@ func (bot *TipBot) sendHandler(ctx context.Context, m *tb.Message) (context.Cont // check and print all commands // If the send is a reply, then trigger /tip handler - if m.IsReply() && m.Chat.Type != tb.ChatPrivate { - return bot.tipHandler(ctx, m) + if ctx.Message().IsReply() && ctx.Message().Chat.Type != tb.ChatPrivate { + return bot.tipHandler(ctx) } @@ -80,21 +81,21 @@ func (bot *TipBot) sendHandler(ctx context.Context, m *tb.Message) (context.Cont // } // get send amount, returns 0 if no amount is given - amount, err := decodeAmountFromCommand(m.Text) + amount, err := decodeAmountFromCommand(ctx.Text()) // info: /send 10 DEMANDS an amount, while /send also works without // todo: /send should also invoke amount input dialog if no amount is given // CHECK whether first or second argument is a LIGHTNING ADDRESS arg := "" - if len(strings.Split(m.Text, " ")) > 2 { - arg, err = getArgumentFromCommand(m.Text, 2) - } else if len(strings.Split(m.Text, " ")) == 2 { - arg, err = getArgumentFromCommand(m.Text, 1) + if len(strings.Split(ctx.Message().Text, " ")) > 2 { + arg, err = getArgumentFromCommand(ctx.Message().Text, 2) + } else if len(strings.Split(ctx.Message().Text, " ")) == 2 { + arg, err = getArgumentFromCommand(ctx.Message().Text, 1) } if err == nil { if lightning.IsLightningAddress(arg) { // lightning address, send to that address - ctx, err = bot.sendToLightningAddress(ctx, m, arg, amount) + ctx, err = bot.sendToLightningAddress(ctx, arg, amount) if err != nil { log.Errorln(err.Error()) return ctx, err @@ -104,16 +105,16 @@ func (bot *TipBot) sendHandler(ctx context.Context, m *tb.Message) (context.Cont } // is a user given? - arg, err = getArgumentFromCommand(m.Text, 1) - if err != nil && m.Chat.Type == tb.ChatPrivate { - _, err = bot.askForUser(ctx, "", "CreateSendState", m.Text) + arg, err = getArgumentFromCommand(ctx.Message().Text, 1) + if err != nil && ctx.Message().Chat.Type == tb.ChatPrivate { + _, err = bot.askForUser(ctx, "", "CreateSendState", ctx.Message().Text) return ctx, err } // is an amount given? - amount, err = decodeAmountFromCommand(m.Text) - if (err != nil || amount < 1) && m.Chat.Type == tb.ChatPrivate { - _, err = bot.askForAmount(ctx, "", "CreateSendState", 0, 0, m.Text) + amount, err = decodeAmountFromCommand(ctx.Message().Text) + if (err != nil || amount < 1) && ctx.Message().Chat.Type == tb.ChatPrivate { + _, err = bot.askForAmount(ctx, "", "CreateSendState", 0, 0, ctx.Message().Text) return ctx, err } @@ -122,24 +123,24 @@ func (bot *TipBot) sendHandler(ctx context.Context, m *tb.Message) (context.Cont errmsg := fmt.Sprintf("[/send] Error: Send amount not valid.") log.Warnln(errmsg) // immediately delete if the amount is bullshit - NewMessage(m, WithDuration(0, bot)) - bot.trySendMessage(m.Sender, helpSendUsage(ctx, Translate(ctx, "sendValidAmountMessage"))) + NewMessage(ctx.Message(), WithDuration(0, bot)) + bot.trySendMessage(ctx.Sender(), helpSendUsage(ctx, Translate(ctx, "sendValidAmountMessage"))) return ctx, err } // SEND COMMAND IS VALID // check for memo in command - sendMemo := GetMemoFromCommand(m.Text, 3) + sendMemo := GetMemoFromCommand(ctx.Message().Text, 3) toUserStrMention := "" toUserStrWithoutAt := "" // check for user in command, accepts user mention or plain username without @ - if len(m.Entities) > 1 && m.Entities[1].Type == "mention" { - toUserStrMention = m.Text[m.Entities[1].Offset : m.Entities[1].Offset+m.Entities[1].Length] + if len(ctx.Message().Entities) > 1 && ctx.Message().Entities[1].Type == "mention" { + toUserStrMention = ctx.Message().Text[ctx.Message().Entities[1].Offset : ctx.Message().Entities[1].Offset+ctx.Message().Entities[1].Length] toUserStrWithoutAt = strings.TrimPrefix(toUserStrMention, "@") } else { - toUserStrWithoutAt, err = getArgumentFromCommand(m.Text, 2) + toUserStrWithoutAt, err = getArgumentFromCommand(ctx.Message().Text, 2) if err != nil { log.Errorln(err.Error()) return ctx, err @@ -148,24 +149,24 @@ func (bot *TipBot) sendHandler(ctx context.Context, m *tb.Message) (context.Cont toUserStrMention = "@" + toUserStrWithoutAt } - err = bot.parseCmdDonHandler(ctx, m) + err = bot.parseCmdDonHandler(ctx) if err == nil { return ctx, errors.Create(errors.InvalidSyntaxError) } toUserDb, err := GetUserByTelegramUsername(toUserStrWithoutAt, *bot) if err != nil { - NewMessage(m, WithDuration(0, bot)) + NewMessage(ctx.Message(), WithDuration(0, bot)) // cut username if it's too long if len(toUserStrMention) > 100 { toUserStrMention = toUserStrMention[:100] } - bot.trySendMessage(m.Sender, fmt.Sprintf(Translate(ctx, "sendUserHasNoWalletMessage"), str.MarkdownEscape(toUserStrMention))) + bot.trySendMessage(ctx.Message().Sender, fmt.Sprintf(Translate(ctx, "sendUserHasNoWalletMessage"), str.MarkdownEscape(toUserStrMention))) return ctx, err } if user.ID == toUserDb.ID { - bot.trySendMessage(m.Sender, Translate(ctx, "sendYourselfMessage")) + bot.trySendMessage(ctx.Message().Sender, Translate(ctx, "sendYourselfMessage")) return ctx, errors.Create(errors.SelfPaymentError) } @@ -175,7 +176,7 @@ func (bot *TipBot) sendHandler(ctx context.Context, m *tb.Message) (context.Cont confirmText = confirmText + fmt.Sprintf(Translate(ctx, "confirmSendAppendMemo"), str.MarkdownEscape(sendMemo)) } // object that holds all information about the send payment - id := fmt.Sprintf("send-%d-%d-%s", m.Sender.ID, amount, RandStringRunes(5)) + id := fmt.Sprintf("send-%d-%d-%s", ctx.Message().Sender.ID, amount, RandStringRunes(5)) sendData := &SendData{ From: user, Base: storage.New(storage.ID(id)), @@ -191,9 +192,9 @@ func (bot *TipBot) sendHandler(ctx context.Context, m *tb.Message) (context.Cont sendDataJson, err := json.Marshal(sendData) if err != nil { - NewMessage(m, WithDuration(0, bot)) + NewMessage(ctx.Message(), WithDuration(0, bot)) log.Printf("[/send] Error: %s\n", err.Error()) - bot.trySendMessage(m.Sender, fmt.Sprint(Translate(ctx, "errorTryLaterMessage"))) + bot.trySendMessage(ctx.Message().Sender, fmt.Sprint(Translate(ctx, "errorTryLaterMessage"))) return ctx, err } // save the send data to the Database @@ -209,10 +210,10 @@ func (bot *TipBot) sendHandler(ctx context.Context, m *tb.Message) (context.Cont sendButton, cancelButton), ) - if m.Private() { - bot.trySendMessage(m.Chat, confirmText, sendConfirmationMenu) + if ctx.Message().Private() { + bot.trySendMessage(ctx.Chat(), confirmText, sendConfirmationMenu) } else { - bot.tryReplyMessage(m, confirmText, sendConfirmationMenu) + bot.tryReplyMessage(ctx.Message(), confirmText, sendConfirmationMenu) } return ctx, nil } @@ -221,7 +222,7 @@ func (bot *TipBot) sendHandler(ctx context.Context, m *tb.Message) (context.Cont // it will pop up a new keyboard with the last interacted contacts to send funds to // then, the flow is handled as if the user entered /send (then ask for contacts from keyboard or entry, // then ask for an amount). -func (bot *TipBot) keyboardSendHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) keyboardSendHandler(ctx intercept.Context) (intercept.Context, error) { user := LoadUser(ctx) if user.Wallet == nil { return ctx, errors.Create(errors.UserNoWalletError) @@ -243,8 +244,8 @@ func (bot *TipBot) keyboardSendHandler(ctx context.Context, m *tb.Message) (cont // if no contact is found (one entry will always be inside, it's the enter user button) // immediatelly go to the send handler if len(sendToButtons) == 1 { - m.Text = "/send" - return bot.sendHandler(ctx, m) + ctx.Message().Text = "/send" + return bot.sendHandler(ctx) } // Attention! We need to ues the original Telegram.Send command here! @@ -258,8 +259,8 @@ func (bot *TipBot) keyboardSendHandler(ctx context.Context, m *tb.Message) (cont } // sendHandler invoked when user clicked send on payment confirmation -func (bot *TipBot) confirmSendHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { - tx := &SendData{Base: storage.New(storage.ID(c.Data))} +func (bot *TipBot) confirmSendHandler(ctx intercept.Context) (intercept.Context, error) { + tx := &SendData{Base: storage.New(storage.ID(ctx.Data()))} mutex.LockWithContext(ctx, tx.ID) defer mutex.UnlockWithContext(ctx, tx.ID) sn, err := tx.Get(tx, bot.Bunt) @@ -269,7 +270,7 @@ func (bot *TipBot) confirmSendHandler(ctx context.Context, c *tb.Callback) (cont } sendData := sn.(*SendData) // onnly the correct user can press - if sendData.From.Telegram.ID != c.Sender.ID { + if sendData.From.Telegram.ID != ctx.Callback().Sender.ID { return ctx, errors.Create(errors.UnknownError) } if !sendData.Active { @@ -297,7 +298,7 @@ func (bot *TipBot) confirmSendHandler(ctx context.Context, c *tb.Callback) (cont to, err := GetLnbitsUser(&tb.User{ID: toId, Username: toUserStrWithoutAt}, *bot) if err != nil { log.Errorln(err.Error()) - bot.tryDeleteMessage(c.Message) + bot.tryDeleteMessage(ctx.Callback().Message) return ctx, err } toUserStrMd := GetUserStrMd(to.Telegram) @@ -314,7 +315,7 @@ func (bot *TipBot) confirmSendHandler(ctx context.Context, c *tb.Callback) (cont // bot.trySendMessage(c.Sender, sendErrorMessage) errmsg := fmt.Sprintf("[/send] Error: Transaction failed. %s", err.Error()) log.Errorln(errmsg) - bot.tryEditMessage(c.Message, i18n.Translate(sendData.LanguageCode, "sendErrorMessage"), &tb.ReplyMarkup{}) + bot.tryEditMessage(ctx.Callback().Message, i18n.Translate(sendData.LanguageCode, "sendErrorMessage"), &tb.ReplyMarkup{}) return ctx, errors.Create(errors.UnknownError) } sendData.Inactivate(sendData, bot.Bunt) @@ -324,16 +325,16 @@ func (bot *TipBot) confirmSendHandler(ctx context.Context, c *tb.Callback) (cont // notify to user bot.trySendMessage(to.Telegram, fmt.Sprintf(i18n.Translate(to.Telegram.LanguageCode, "sendReceivedMessage"), fromUserStrMd, amount)) // bot.trySendMessage(from.Telegram, fmt.Sprintf(Translate(ctx, "sendSentMessage"), amount, toUserStrMd)) - if c.Message.Private() { + if ctx.Callback().Message.Private() { // if the command was invoked in private chat // the edit below was cool, but we need to get rid of the replymarkup inline keyboard thingy for the main menu to pop up // bot.tryEditMessage(c.Message, fmt.Sprintf(i18n.Translate(sendData.LanguageCode, "sendSentMessage"), amount, toUserStrMd), &tb.ReplyMarkup{}) - bot.tryDeleteMessage(c.Message) - bot.trySendMessage(c.Sender, fmt.Sprintf(i18n.Translate(sendData.LanguageCode, "sendSentMessage"), amount, toUserStrMd)) + bot.tryDeleteMessage(ctx.Callback().Message) + bot.trySendMessage(ctx.Callback().Sender, fmt.Sprintf(i18n.Translate(sendData.LanguageCode, "sendSentMessage"), amount, toUserStrMd)) } else { // if the command was invoked in group chat - bot.trySendMessage(c.Sender, fmt.Sprintf(i18n.Translate(from.Telegram.LanguageCode, "sendSentMessage"), amount, toUserStrMd)) - bot.tryEditMessage(c.Message, fmt.Sprintf(i18n.Translate(sendData.LanguageCode, "sendPublicSentMessage"), amount, fromUserStrMd, toUserStrMd), &tb.ReplyMarkup{}) + bot.trySendMessage(ctx.Callback().Sender, fmt.Sprintf(i18n.Translate(from.Telegram.LanguageCode, "sendSentMessage"), amount, toUserStrMd)) + bot.tryEditMessage(ctx.Callback().Message, fmt.Sprintf(i18n.Translate(sendData.LanguageCode, "sendPublicSentMessage"), amount, fromUserStrMd, toUserStrMd), &tb.ReplyMarkup{}) } // send memo if it was present if len(sendMemo) > 0 { @@ -344,8 +345,9 @@ func (bot *TipBot) confirmSendHandler(ctx context.Context, c *tb.Callback) (cont } // cancelPaymentHandler invoked when user clicked cancel on payment confirmation -func (bot *TipBot) cancelSendHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) cancelSendHandler(ctx intercept.Context) (intercept.Context, error) { // reset state immediately + c := ctx.Callback() user := LoadUser(ctx) ResetUserState(user, bot) tx := &SendData{Base: storage.New(storage.ID(c.Data))} @@ -363,7 +365,7 @@ func (bot *TipBot) cancelSendHandler(ctx context.Context, c *tb.Callback) (conte return ctx, errors.Create(errors.UnknownError) } // delete and send instead of edit for the keyboard to pop up after sending - bot.tryDeleteMessage(c.Message) + bot.tryDeleteMessage(c) bot.trySendMessage(c.Message.Chat, i18n.Translate(sendData.LanguageCode, "sendCancelledMessage")) sendData.Inactivate(sendData, bot.Bunt) return ctx, nil diff --git a/internal/telegram/shop.go b/internal/telegram/shop.go index 01ebcef..115e199 100644 --- a/internal/telegram/shop.go +++ b/internal/telegram/shop.go @@ -7,6 +7,8 @@ import ( "strings" "time" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" + "github.com/LightningTipBot/LightningTipBot/internal/errors" "github.com/LightningTipBot/LightningTipBot/internal/i18n" @@ -16,7 +18,7 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/str" "github.com/eko/gocache/store" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) type ShopView struct { @@ -26,7 +28,6 @@ type ShopView struct { Page int Message *tb.Message StatusMessages []*tb.Message - Chat *tb.Chat } type ShopItem struct { @@ -81,7 +82,7 @@ func (shop *Shop) getItem(itemId string) (item ShopItem, ok bool) { } var ( - shopKeyboard = &tb.ReplyMarkup{ResizeReplyKeyboard: false} + shopKeyboard = &tb.ReplyMarkup{ResizeKeyboard: false} browseShopButton = shopKeyboard.Data("Browse shops", "shops_browse") shopNewShopButton = shopKeyboard.Data("New Shop", "shops_newshop") shopDeleteShopButton = shopKeyboard.Data("Delete Shops", "shops_deleteshop") @@ -114,7 +115,8 @@ var ( ) // shopItemPriceHandler is invoked when the user presses the item settings button to set a price -func (bot *TipBot) shopItemPriceHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopItemPriceHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopItemPriceHandler] %s", c.Data) user := LoadUser(ctx) shopView, err := bot.getUserShopview(ctx, user) @@ -138,7 +140,8 @@ func (bot *TipBot) shopItemPriceHandler(ctx context.Context, c *tb.Callback) (co } // enterShopItemPriceHandler is invoked when the user enters a price amount -func (bot *TipBot) enterShopItemPriceHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) enterShopItemPriceHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() log.Debugf("[enterShopItemPriceHandler] %s", m.Text) user := LoadUser(ctx) shopView, err := bot.getUserShopview(ctx, user) @@ -172,9 +175,9 @@ func (bot *TipBot) enterShopItemPriceHandler(ctx context.Context, m *tb.Message) } } - if amount > 200 { - bot.sendStatusMessageAndDelete(ctx, m.Sender, fmt.Sprintf("â„šī¸ During alpha testing, price can be max 200 sat.")) - amount = 200 + if amount > 2000 { + bot.sendStatusMessageAndDelete(ctx, m.Sender, "â„šī¸ During testing, price can be max 2000 sat.") + amount = 2000 } item.Price = amount shop.Items[item.ID] = item @@ -191,7 +194,8 @@ func (bot *TipBot) enterShopItemPriceHandler(ctx context.Context, m *tb.Message) } // shopItemPriceHandler is invoked when the user presses the item settings button to set a item title -func (bot *TipBot) shopItemTitleHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopItemTitleHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopItemTitleHandler] %s", c.Data) user := LoadUser(ctx) shopView, err := bot.getUserShopview(ctx, user) @@ -215,7 +219,8 @@ func (bot *TipBot) shopItemTitleHandler(ctx context.Context, c *tb.Callback) (co } // enterShopItemTitleHandler is invoked when the user enters a title of the item -func (bot *TipBot) enterShopItemTitleHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) enterShopItemTitleHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() log.Debugf("[enterShopItemTitleHandler] %s", m.Text) user := LoadUser(ctx) shopView, err := bot.getUserShopview(ctx, user) @@ -264,7 +269,8 @@ func (bot *TipBot) enterShopItemTitleHandler(ctx context.Context, m *tb.Message) } // shopItemSettingsHandler is invoked when the user presses the item settings button -func (bot *TipBot) shopItemSettingsHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopItemSettingsHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopItemSettingsHandler] %s", c.Data) user := LoadUser(ctx) shopView, err := bot.getUserShopview(ctx, user) @@ -286,7 +292,8 @@ func (bot *TipBot) shopItemSettingsHandler(ctx context.Context, c *tb.Callback) } // shopItemPriceHandler is invoked when the user presses the item settings button to set a item title -func (bot *TipBot) shopItemDeleteHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopItemDeleteHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopItemDeleteHandler] %s", c.Data) user := LoadUser(ctx) shopView, err := bot.getUserShopview(ctx, user) @@ -335,7 +342,8 @@ func (bot *TipBot) shopItemDeleteHandler(ctx context.Context, c *tb.Callback) (c } // displayShopItemHandler is invoked when the user presses the back button in the item settings -func (bot *TipBot) displayShopItemHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) displayShopItemHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[displayShopItemHandler] c.Data: %s", c.Data) user := LoadUser(ctx) shopView, err := bot.getUserShopview(ctx, user) @@ -357,7 +365,8 @@ func (bot *TipBot) displayShopItemHandler(ctx context.Context, c *tb.Callback) ( } // shopNextItemHandler is invoked when the user presses the next item button -func (bot *TipBot) shopNextItemButtonHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopNextItemButtonHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopNextItemButtonHandler] c.Data: %s", c.Data) user := LoadUser(ctx) // shopView, err := bot.Cache.Get(fmt.Sprintf("shopview-%d", user.Telegram.ID)) @@ -379,7 +388,8 @@ func (bot *TipBot) shopNextItemButtonHandler(ctx context.Context, c *tb.Callback } // shopPrevItemButtonHandler is invoked when the user presses the previous item button -func (bot *TipBot) shopPrevItemButtonHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopPrevItemButtonHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopPrevItemButtonHandler] %s", c.Data) user := LoadUser(ctx) shopView, err := bot.getUserShopview(ctx, user) @@ -388,7 +398,7 @@ func (bot *TipBot) shopPrevItemButtonHandler(ctx context.Context, c *tb.Callback } if shopView.Page == 0 { c.Message.Text = "/shops " + shopView.ShopOwner.Telegram.Username - return bot.shopsHandler(ctx, c.Message) + return bot.shopsHandler(ctx) } if shopView.Page > 0 { @@ -421,9 +431,9 @@ func (bot *TipBot) getItemTitle(ctx context.Context, item *ShopItem) string { // displayShopItem renders the current item in the shopView // requires that the shopview page is already set accordingly // m is the message that will be edited -func (bot *TipBot) displayShopItem(ctx context.Context, m *tb.Message, shop *Shop) *tb.Message { +func (bot *TipBot) displayShopItem(ctx intercept.Context, m *tb.Message, shop *Shop) *tb.Message { user := LoadUser(ctx) - log.Debugf("[displayShopItem] User: %d shop: %s", GetUserStr(user.Telegram), shop.ID) + log.Debugf("[displayShopItem] User: %s shop: %s", GetUserStr(user.Telegram), shop.ID) shopView, err := bot.getUserShopview(ctx, user) if err != nil { log.Errorf("[displayShopItem] %s", err.Error()) @@ -445,7 +455,7 @@ func (bot *TipBot) displayShopItem(ctx context.Context, m *tb.Message, shop *Sho if shopView.Message != nil { bot.tryDeleteMessage(shopView.Message) } - shopView.Message = bot.trySendMessage(shopView.Chat, no_items_message, bot.shopMenu(ctx, shop, &ShopItem{})) + shopView.Message = bot.trySendMessage(shopView.Message.Chat, no_items_message, bot.shopMenu(ctx, shop, &ShopItem{})) } shopView.Page = 0 return shopView.Message @@ -487,7 +497,8 @@ func (bot *TipBot) displayShopItem(ctx context.Context, m *tb.Message, shop *Sho } // shopHandler is invoked when the user enters /shop -func (bot *TipBot) shopHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) shopHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() log.Debugf("[shopHandler] %s", m.Text) if !m.Private() { return ctx, errors.Create(errors.NoPrivateChatError) @@ -498,7 +509,7 @@ func (bot *TipBot) shopHandler(ctx context.Context, m *tb.Message) (context.Cont // when no argument is given, i.e. command is only /shop, load /shops shop := &Shop{} if len(strings.Split(m.Text, " ")) < 2 || !strings.HasPrefix(strings.Split(m.Text, " ")[1], "shop-") { - return bot.shopsHandler(ctx, m) + return bot.shopsHandler(ctx) } else { // else: get shop by shop ID shopID := strings.Split(m.Text, " ")[1] @@ -515,7 +526,6 @@ func (bot *TipBot) shopHandler(ctx context.Context, m *tb.Message) (context.Cont ShopID: shop.ID, Page: 0, ShopOwner: shopOwner, - Chat: m.Chat, } bot.Cache.Set(shopView.ID, shopView, &store.Options{Expiration: 24 * time.Hour}) shopView.Message = bot.displayShopItem(ctx, m, shop) @@ -533,7 +543,8 @@ func (bot *TipBot) shopHandler(ctx context.Context, m *tb.Message) (context.Cont } // shopNewItemHandler is invoked when the user presses the new item button -func (bot *TipBot) shopNewItemHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopNewItemHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopNewItemHandler] %s", c.Data) user := LoadUser(ctx) shop, err := bot.getShop(ctx, c.Data) @@ -562,7 +573,7 @@ func (bot *TipBot) shopNewItemHandler(ctx context.Context, c *tb.Callback) (cont } // addShopItem is a helper function for creating a shop item in the database -func (bot *TipBot) addShopItem(ctx context.Context, shopId string) (*Shop, ShopItem, error) { +func (bot *TipBot) addShopItem(ctx intercept.Context, shopId string) (*Shop, ShopItem, error) { log.Debugf("[addShopItem] shopId: %s", shopId) shop, err := bot.getShop(ctx, shopId) if err != nil { @@ -593,7 +604,8 @@ func (bot *TipBot) addShopItem(ctx context.Context, shopId string) (*Shop, ShopI } // addShopItemPhoto is invoked when the users sends a photo as a new item -func (bot *TipBot) addShopItemPhoto(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) addShopItemPhoto(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() log.Debugf("[addShopItemPhoto] ") user := LoadUser(ctx) if user.Wallet == nil { @@ -644,7 +656,8 @@ func (bot *TipBot) addShopItemPhoto(ctx context.Context, m *tb.Message) (context // ------------------- item files ---------- // shopItemAddItemHandler is invoked when the user presses the new item button -func (bot *TipBot) shopItemAddItemHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopItemAddItemHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopItemAddItemHandler] %s", c.Data) user := LoadUser(ctx) if user.Wallet == nil { @@ -676,7 +689,8 @@ func (bot *TipBot) shopItemAddItemHandler(ctx context.Context, c *tb.Callback) ( } // addItemFileHandler is invoked when the users sends a new file for the item -func (bot *TipBot) addItemFileHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) addItemFileHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() log.Debugf("[addItemFileHandler] ") user := LoadUser(ctx) if user.Wallet == nil { @@ -769,7 +783,8 @@ func (bot *TipBot) addItemFileHandler(ctx context.Context, m *tb.Message) (conte return ctx, nil } -func (bot *TipBot) shopGetItemFilesHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopGetItemFilesHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopGetItemFilesHandler] %s", c.Data) user := LoadUser(ctx) if user.Wallet == nil { @@ -808,7 +823,8 @@ func (bot *TipBot) shopGetItemFilesHandler(ctx context.Context, c *tb.Callback) } // shopConfirmBuyHandler is invoked when the user has confirmed to pay for an item -func (bot *TipBot) shopConfirmBuyHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopConfirmBuyHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopConfirmBuyHandler] %s", c.Data) user := LoadUser(ctx) if user.Wallet == nil { @@ -851,7 +867,7 @@ func (bot *TipBot) shopConfirmBuyHandler(ctx context.Context, c *tb.Callback) (c // bot.trySendMessage(c.Sender, sendErrorMessage) errmsg := fmt.Sprintf("[shop] Error: Transaction failed. %s", err.Error()) log.Errorln(errmsg) - ctx = context.WithValue(ctx, "callback_response", i18n.Translate(user.Telegram.LanguageCode, "sendErrorMessage")) + ctx.Context = context.WithValue(ctx, "callback_response", i18n.Translate(user.Telegram.LanguageCode, "sendErrorMessage")) // bot.trySendMessage(user.Telegram, i18n.Translate(user.Telegram.LanguageCode, "sendErrorMessage"), &tb.ReplyMarkup{}) return ctx, errors.New(errors.UnknownError, err) } @@ -860,7 +876,7 @@ func (bot *TipBot) shopConfirmBuyHandler(ctx context.Context, c *tb.Callback) (c if len(item.Title) > 0 { shopItemTitle = fmt.Sprintf("%s", item.Title) } - ctx = context.WithValue(ctx, "callback_response", "🛍 Purchase successful.") + ctx.Context = context.WithValue(ctx, "callback_response", "🛍 Purchase successful.") bot.trySendMessage(to.Telegram, fmt.Sprintf("🛍 Someone bought `%s` from your shop `%s` for `%d sat`.", str.MarkdownEscape(shopItemTitle), str.MarkdownEscape(shop.Title), amount)) bot.trySendMessage(from.Telegram, fmt.Sprintf("🛍 You bought `%s` from %s's shop `%s` for `%d sat`.", str.MarkdownEscape(shopItemTitle), toUserStrMd, str.MarkdownEscape(shop.Title), amount)) log.Infof("[🛍 shop] %s bought from %s shop: %s item: %s for %d sat.", toUserStr, GetUserStr(to.Telegram), shop.Title, shopItemTitle, amount) @@ -869,7 +885,7 @@ func (bot *TipBot) shopConfirmBuyHandler(ctx context.Context, c *tb.Callback) (c } // shopSendItemFilesToUser is a handler function to send itemID's files to the user -func (bot *TipBot) shopSendItemFilesToUser(ctx context.Context, toUser *lnbits.User, itemID string) { +func (bot *TipBot) shopSendItemFilesToUser(ctx intercept.Context, toUser *lnbits.User, itemID string) { log.Debugf("[shopSendItemFilesToUser] %s -> %s", GetUserStr(toUser.Telegram), itemID) user := LoadUser(ctx) if user.Wallet == nil { @@ -939,12 +955,13 @@ var ShopsTextHelp = "âš ī¸ Shops are still in beta. Expect bugs." var ShopsNoShopsText = "*There are no shops here yet.*" // shopsHandlerCallback is a warpper for shopsHandler for callbacks -func (bot *TipBot) shopsHandlerCallback(ctx context.Context, c *tb.Callback) (context.Context, error) { - return bot.shopsHandler(ctx, c.Message) +func (bot *TipBot) shopsHandlerCallback(ctx intercept.Context) (intercept.Context, error) { + return bot.shopsHandler(ctx) } // shopsHandler is invoked when the user enters /shops -func (bot *TipBot) shopsHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) shopsHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() log.Debugf("[shopsHandler] %s", GetUserStr(m.Sender)) if !m.Private() { return ctx, errors.Create(errors.NoPrivateChatError) @@ -1085,7 +1102,8 @@ func (bot *TipBot) shopsHandler(ctx context.Context, m *tb.Message) (context.Con } // shopsDeleteShopBrowser is invoked when the user clicks on "delete shops" and makes a list of all shops -func (bot *TipBot) shopsDeleteShopBrowser(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopsDeleteShopBrowser(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopsDeleteShopBrowser] %s", c.Data) user := LoadUser(ctx) shops, err := bot.getUserShops(ctx, user) @@ -1108,7 +1126,8 @@ func (bot *TipBot) shopsDeleteShopBrowser(ctx context.Context, c *tb.Callback) ( return ctx, err } -func (bot *TipBot) shopsAskDeleteAllShopsHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopsAskDeleteAllShopsHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopsAskDeleteAllShopsHandler] %s", c.Data) shopResetShopButton := shopKeyboard.Data("âš ī¸ Delete all shops", "shops_reset", c.Data) buttons := []tb.Row{ @@ -1123,7 +1142,8 @@ func (bot *TipBot) shopsAskDeleteAllShopsHandler(ctx context.Context, c *tb.Call } // shopsLinkShopBrowser is invoked when the user clicks on "shop links" and makes a list of all shops -func (bot *TipBot) shopsLinkShopBrowser(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopsLinkShopBrowser(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopsLinkShopBrowser] %s", c.Data) user := LoadUser(ctx) shops, err := bot.getUserShops(ctx, user) @@ -1145,7 +1165,8 @@ func (bot *TipBot) shopsLinkShopBrowser(ctx context.Context, c *tb.Callback) (co } // shopSelectLink is invoked when the user has chosen a shop to get the link of -func (bot *TipBot) shopSelectLink(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopSelectLink(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopSelectLink] %s", c.Data) shop, _ := bot.getShop(ctx, c.Data) if shop.Owner.Telegram.ID != c.Sender.ID { @@ -1156,7 +1177,8 @@ func (bot *TipBot) shopSelectLink(ctx context.Context, c *tb.Callback) (context. } // shopsLinkShopBrowser is invoked when the user clicks on "shop links" and makes a list of all shops -func (bot *TipBot) shopsRenameShopBrowser(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopsRenameShopBrowser(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopsRenameShopBrowser] %s", c.Data) user := LoadUser(ctx) shops, err := bot.getUserShops(ctx, user) @@ -1178,7 +1200,8 @@ func (bot *TipBot) shopsRenameShopBrowser(ctx context.Context, c *tb.Callback) ( } // shopSelectLink is invoked when the user has chosen a shop to get the link of -func (bot *TipBot) shopSelectRename(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopSelectRename(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopSelectRename] %s", c.Data) user := LoadUser(ctx) shop, _ := bot.getShop(ctx, c.Data) @@ -1192,7 +1215,8 @@ func (bot *TipBot) shopSelectRename(ctx context.Context, c *tb.Callback) (contex } // shopsDescriptionHandler is invoked when the user clicks on "description" to set a shop description -func (bot *TipBot) shopsDescriptionHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopsDescriptionHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopsDescriptionHandler] %s", c.Data) user := LoadUser(ctx) shops, err := bot.getUserShops(ctx, user) @@ -1206,7 +1230,8 @@ func (bot *TipBot) shopsDescriptionHandler(ctx context.Context, c *tb.Callback) } // enterShopsDescriptionHandler is invoked when the user enters the shop title -func (bot *TipBot) enterShopsDescriptionHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) enterShopsDescriptionHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() log.Debugf("[enterShopsDescriptionHandler] %s", m.Text) user := LoadUser(ctx) shops, err := bot.getUserShops(ctx, user) @@ -1239,13 +1264,14 @@ func (bot *TipBot) enterShopsDescriptionHandler(ctx context.Context, m *tb.Messa // time.Sleep(time.Duration(5) * time.Second) // bot.shopViewDeleteAllStatusMsgs(ctx, user) // }() - bot.shopsHandler(ctx, m) + bot.shopsHandler(ctx) bot.tryDeleteMessage(m) return ctx, nil } // shopsResetHandler is invoked when the user clicks button to reset shops completely -func (bot *TipBot) shopsResetHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopsResetHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopsResetHandler] %s", c.Data) user := LoadUser(ctx) shops, err := bot.getUserShops(ctx, user) @@ -1262,11 +1288,12 @@ func (bot *TipBot) shopsResetHandler(ctx context.Context, c *tb.Callback) (conte // time.Sleep(time.Duration(5) * time.Second) // bot.shopViewDeleteAllStatusMsgs(ctx, user) // }() - return bot.shopsHandlerCallback(ctx, c) + return bot.shopsHandlerCallback(ctx) } // shopSelect is invoked when the user has selected a shop to browse -func (bot *TipBot) shopSelect(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopSelect(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopSelect] %s", c.Data) shop, _ := bot.getShop(ctx, c.Data) user := LoadUser(ctx) @@ -1292,12 +1319,13 @@ func (bot *TipBot) shopSelect(ctx context.Context, c *tb.Callback) (context.Cont // } shopView.Message = shopMessage log.Infof("[🛍 shop] %s erntering shop %s.", GetUserStr(user.Telegram), shop.ID) - ctx = context.WithValue(ctx, "callback_response", fmt.Sprintf("🛍 You are browsing %s", shop.Title)) + ctx.Context = context.WithValue(ctx, "callback_response", fmt.Sprintf("🛍 You are browsing %s", shop.Title)) return ctx, bot.Cache.Set(shopView.ID, shopView, &store.Options{Expiration: 24 * time.Hour}) } // shopSelectDelete is invoked when the user has chosen a shop to delete -func (bot *TipBot) shopSelectDelete(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopSelectDelete(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopSelectDelete] %s", c.Data) shop, _ := bot.getShop(ctx, c.Data) user := LoadUser(ctx) @@ -1323,11 +1351,12 @@ func (bot *TipBot) shopSelectDelete(ctx context.Context, c *tb.Callback) (contex log.Infof("[🛍 shop] %s deleted shop %s.", GetUserStr(user.Telegram), shop.ID) // then update buttons - return bot.shopsDeleteShopBrowser(ctx, c) + return bot.shopsDeleteShopBrowser(ctx) } // shopsBrowser makes a button list of all shops the user can browse -func (bot *TipBot) shopsBrowser(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopsBrowser(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopsBrowser] %s", c.Data) user := LoadUser(ctx) shopView, err := bot.getUserShopview(ctx, user) @@ -1356,7 +1385,8 @@ func (bot *TipBot) shopsBrowser(ctx context.Context, c *tb.Callback) (context.Co } // shopItemSettingsHandler is invoked when the user presses the shop settings button -func (bot *TipBot) shopSettingsHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopSettingsHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopSettingsHandler] %s", c.Data) user := LoadUser(ctx) shopView, err := bot.getUserShopview(ctx, user) @@ -1376,7 +1406,8 @@ func (bot *TipBot) shopSettingsHandler(ctx context.Context, c *tb.Callback) (con } // shopNewShopHandler is invoked when the user presses the new shop button -func (bot *TipBot) shopNewShopHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) shopNewShopHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() log.Debugf("[shopNewShopHandler] %s", c.Data) user := LoadUser(ctx) shops, err := bot.getUserShops(ctx, user) @@ -1396,7 +1427,8 @@ func (bot *TipBot) shopNewShopHandler(ctx context.Context, c *tb.Callback) (cont } // enterShopTitleHandler is invoked when the user enters the shop title -func (bot *TipBot) enterShopTitleHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) enterShopTitleHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() log.Debugf("[enterShopTitleHandler] %s", m.Text) user := LoadUser(ctx) // read item from user.StateData @@ -1429,7 +1461,10 @@ func (bot *TipBot) enterShopTitleHandler(ctx context.Context, m *tb.Message) (co // time.Sleep(time.Duration(5) * time.Second) // bot.shopViewDeleteAllStatusMsgs(ctx, user) // }() - bot.shopsHandler(ctx, m) + ctx, err = bot.shopsHandler(ctx) + if err != nil { + log.Errorf("[shop] failed shopshandler") + } bot.tryDeleteMessage(m) log.Infof("[🛍 shop] %s added new shop %s.", GetUserStr(user.Telegram), shop.ID) return ctx, nil diff --git a/internal/telegram/shop_helpers.go b/internal/telegram/shop_helpers.go index c04c247..3cb52ed 100644 --- a/internal/telegram/shop_helpers.go +++ b/internal/telegram/shop_helpers.go @@ -1,22 +1,19 @@ package telegram import ( - "context" "fmt" - "time" - - "github.com/LightningTipBot/LightningTipBot/internal/runtime/mutex" - "github.com/LightningTipBot/LightningTipBot/internal/storage" - "github.com/LightningTipBot/LightningTipBot/internal/lnbits" "github.com/LightningTipBot/LightningTipBot/internal/runtime" - + "github.com/LightningTipBot/LightningTipBot/internal/runtime/mutex" + "github.com/LightningTipBot/LightningTipBot/internal/storage" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "github.com/eko/gocache/store" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" + "time" ) -func (bot TipBot) shopsMainMenu(ctx context.Context, shops *Shops) *tb.ReplyMarkup { +func (bot TipBot) shopsMainMenu(ctx intercept.Context, shops *Shops) *tb.ReplyMarkup { browseShopButton := shopKeyboard.Data("🛍 Browse shops", "shops_browse", shops.ID) shopNewShopButton := shopKeyboard.Data("✅ New Shop", "shops_newshop", shops.ID) shopSettingsButton := shopKeyboard.Data("âš™ī¸ Settings", "shops_settings", shops.ID) @@ -35,7 +32,7 @@ func (bot TipBot) shopsMainMenu(ctx context.Context, shops *Shops) *tb.ReplyMark return shopKeyboard } -func (bot TipBot) shopsSettingsMenu(ctx context.Context, shops *Shops) *tb.ReplyMarkup { +func (bot TipBot) shopsSettingsMenu(ctx intercept.Context, shops *Shops) *tb.ReplyMarkup { shopShopsButton := shopKeyboard.Data("âŦ…ī¸ Back", "shops_shops", shops.ID) shopLinkShopButton := shopKeyboard.Data("🔗 Shop links", "shops_linkshop", shops.ID) shopRenameShopButton := shopKeyboard.Data("âŒ¨ī¸ Rename a shop", "shops_renameshop", shops.ID) @@ -66,7 +63,7 @@ func (bot TipBot) shopsSettingsMenu(ctx context.Context, shops *Shops) *tb.Reply } // shopItemSettingsMenu builds the buttons of the item settings -func (bot TipBot) shopItemSettingsMenu(ctx context.Context, shop *Shop, item *ShopItem) *tb.ReplyMarkup { +func (bot TipBot) shopItemSettingsMenu(ctx intercept.Context, shop *Shop, item *ShopItem) *tb.ReplyMarkup { shopItemPriceButton = shopKeyboard.Data("đŸ’¯ Set price", "shop_itemprice", item.ID) shopItemDeleteButton = shopKeyboard.Data("đŸšĢ Delete item", "shop_itemdelete", item.ID) shopItemTitleButton = shopKeyboard.Data("âŒ¨ī¸ Set title", "shop_itemtitle", item.ID) @@ -86,7 +83,7 @@ func (bot TipBot) shopItemSettingsMenu(ctx context.Context, shop *Shop, item *Sh } // shopItemConfirmBuyMenu builds the buttons to confirm a purchase -func (bot TipBot) shopItemConfirmBuyMenu(ctx context.Context, shop *Shop, item *ShopItem) *tb.ReplyMarkup { +func (bot TipBot) shopItemConfirmBuyMenu(ctx intercept.Context, shop *Shop, item *ShopItem) *tb.ReplyMarkup { shopItemBuyButton = shopKeyboard.Data(fmt.Sprintf("💸 Pay %d sat", item.Price), "shop_itembuy", item.ID) shopItemCancelBuyButton = shopKeyboard.Data("âŦ…ī¸ Back", "shop_itemcancelbuy", item.ID) buttons := []tb.Row{} @@ -99,7 +96,7 @@ func (bot TipBot) shopItemConfirmBuyMenu(ctx context.Context, shop *Shop, item * } // shopMenu builds the buttons in the item browser -func (bot TipBot) shopMenu(ctx context.Context, shop *Shop, item *ShopItem) *tb.ReplyMarkup { +func (bot TipBot) shopMenu(ctx intercept.Context, shop *Shop, item *ShopItem) *tb.ReplyMarkup { user := LoadUser(ctx) shopView, err := bot.getUserShopview(ctx, user) if err != nil { @@ -152,7 +149,7 @@ func (bot *TipBot) makseShopSelectionButtons(shops []*Shop, uniqueString string) // -------------- ShopView -------------- // getUserShopview returns ShopView object from cache that holds information about the user's current browsing view -func (bot *TipBot) getUserShopview(ctx context.Context, user *lnbits.User) (shopView ShopView, err error) { +func (bot *TipBot) getUserShopview(ctx intercept.Context, user *lnbits.User) (shopView ShopView, err error) { sv, err := bot.Cache.Get(fmt.Sprintf("shopview-%d", user.Telegram.ID)) if err != nil { return @@ -160,7 +157,7 @@ func (bot *TipBot) getUserShopview(ctx context.Context, user *lnbits.User) (shop shopView = sv.(ShopView) return } -func (bot *TipBot) shopViewDeleteAllStatusMsgs(ctx context.Context, user *lnbits.User) (shopView ShopView, err error) { +func (bot *TipBot) shopViewDeleteAllStatusMsgs(ctx intercept.Context, user *lnbits.User) (shopView ShopView, err error) { mutex.Lock(fmt.Sprintf("shopview-delete-%d", user.Telegram.ID)) defer mutex.Unlock(fmt.Sprintf("shopview-delete-%d", user.Telegram.ID)) shopView, err = bot.getUserShopview(ctx, user) @@ -182,7 +179,7 @@ func deleteStatusMessages(messages []*tb.Message, bot *TipBot) { // sendStatusMessage adds a status message to the shopVoew.statusMessages // slide and sends a status message to the user. -func (bot *TipBot) sendStatusMessage(ctx context.Context, to tb.Recipient, what interface{}, options ...interface{}) (msg *tb.Message) { +func (bot *TipBot) sendStatusMessage(ctx intercept.Context, to tb.Recipient, what interface{}, options ...interface{}) (msg *tb.Message) { user := LoadUser(ctx) id := fmt.Sprintf("shopview-delete-%d", user.Telegram.ID) @@ -201,7 +198,7 @@ func (bot *TipBot) sendStatusMessage(ctx context.Context, to tb.Recipient, what // sendStatusMessageAndDelete invokes sendStatusMessage and creates // a ticker to delete all status messages after 5 seconds. -func (bot *TipBot) sendStatusMessageAndDelete(ctx context.Context, to tb.Recipient, what interface{}, options ...interface{}) (msg *tb.Message) { +func (bot *TipBot) sendStatusMessageAndDelete(ctx intercept.Context, to tb.Recipient, what interface{}, options ...interface{}) (msg *tb.Message) { user := LoadUser(ctx) id := fmt.Sprintf("shopview-delete-%d", user.Telegram.ID) statusMsg := bot.sendStatusMessage(ctx, to, what, options...) @@ -222,7 +219,7 @@ func (bot *TipBot) sendStatusMessageAndDelete(ctx context.Context, to tb.Recipie // --------------- Shop --------------- // initUserShops is a helper function for creating a Shops for the user in the database -func (bot *TipBot) initUserShops(ctx context.Context, user *lnbits.User) (*Shops, error) { +func (bot *TipBot) initUserShops(ctx intercept.Context, user *lnbits.User) (*Shops, error) { id := fmt.Sprintf("shops-%d", user.Telegram.ID) shops := &Shops{ Base: storage.New(storage.ID(id)), @@ -235,7 +232,7 @@ func (bot *TipBot) initUserShops(ctx context.Context, user *lnbits.User) (*Shops } // getUserShops returns the Shops for the user -func (bot *TipBot) getUserShops(ctx context.Context, user *lnbits.User) (*Shops, error) { +func (bot *TipBot) getUserShops(ctx intercept.Context, user *lnbits.User) (*Shops, error) { tx := &Shops{Base: storage.New(storage.ID(fmt.Sprintf("shops-%d", user.Telegram.ID)))} sn, err := tx.Get(tx, bot.ShopBunt) if err != nil { @@ -247,7 +244,7 @@ func (bot *TipBot) getUserShops(ctx context.Context, user *lnbits.User) (*Shops, } // addUserShop adds a new Shop to the Shops of a user -func (bot *TipBot) addUserShop(ctx context.Context, user *lnbits.User) (*Shop, error) { +func (bot *TipBot) addUserShop(ctx intercept.Context, user *lnbits.User) (*Shop, error) { shops, err := bot.getUserShops(ctx, user) if err != nil { return &Shop{}, err @@ -270,7 +267,7 @@ func (bot *TipBot) addUserShop(ctx context.Context, user *lnbits.User) (*Shop, e } // getShop returns the Shop of a given ID -func (bot *TipBot) getShop(ctx context.Context, shopId string) (*Shop, error) { +func (bot *TipBot) getShop(ctx intercept.Context, shopId string) (*Shop, error) { tx := &Shop{Base: storage.New(storage.ID(shopId))} // immediatelly set intransaction to block duplicate calls sn, err := tx.Get(tx, bot.ShopBunt) diff --git a/internal/telegram/start.go b/internal/telegram/start.go index 5e0de37..f31a67e 100644 --- a/internal/telegram/start.go +++ b/internal/telegram/start.go @@ -4,6 +4,7 @@ import ( "context" stderrors "errors" "fmt" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "strconv" "time" @@ -15,34 +16,34 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/lnbits" "github.com/LightningTipBot/LightningTipBot/internal/str" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" "gorm.io/gorm" ) -func (bot TipBot) startHandler(ctx context.Context, m *tb.Message) (context.Context, error) { - if !m.Private() { +func (bot TipBot) startHandler(ctx intercept.Context) (intercept.Context, error) { + if !ctx.Message().Private() { return ctx, errors.Create(errors.NoPrivateChatError) } // ATTENTION: DO NOT CALL ANY HANDLER BEFORE THE WALLET IS CREATED // WILL RESULT IN AN ENDLESS LOOP OTHERWISE // bot.helpHandler(m) - log.Printf("[â­ī¸ /start] New user: %s (%d)\n", GetUserStr(m.Sender), m.Sender.ID) - walletCreationMsg := bot.trySendMessageEditable(m.Sender, Translate(ctx, "startSettingWalletMessage")) - user, err := bot.initWallet(m.Sender) + log.Printf("[â­ī¸ /start] New user: %s (%d)\n", GetUserStr(ctx.Sender()), ctx.Sender().ID) + walletCreationMsg := bot.trySendMessageEditable(ctx.Sender(), Translate(ctx, "startSettingWalletMessage")) + user, err := bot.initWallet(ctx.Sender()) if err != nil { log.Errorln(fmt.Sprintf("[startHandler] Error with initWallet: %s", err.Error())) bot.tryEditMessage(walletCreationMsg, Translate(ctx, "startWalletErrorMessage")) return ctx, err } bot.tryDeleteMessage(walletCreationMsg) - ctx = context.WithValue(ctx, "user", user) - bot.helpHandler(ctx, m) - bot.trySendMessage(m.Sender, Translate(ctx, "startWalletReadyMessage")) - bot.balanceHandler(ctx, m) + ctx.Context = context.WithValue(ctx, "user", user) + bot.helpHandler(ctx) + bot.trySendMessage(ctx.Sender(), Translate(ctx, "startWalletReadyMessage")) + bot.balanceHandler(ctx) // send the user a warning about the fact that they need to set a username - if len(m.Sender.Username) == 0 { - bot.trySendMessage(m.Sender, Translate(ctx, "startNoUsernameMessage"), tb.NoPreview) + if len(ctx.Sender().Username) == 0 { + bot.trySendMessage(ctx.Sender(), Translate(ctx, "startNoUsernameMessage"), tb.NoPreview) } return ctx, nil } diff --git a/internal/telegram/state.go b/internal/telegram/state.go index fd6ee12..f3135c2 100644 --- a/internal/telegram/state.go +++ b/internal/telegram/state.go @@ -1,12 +1,11 @@ package telegram import ( - "context" "github.com/LightningTipBot/LightningTipBot/internal/lnbits" - tb "gopkg.in/lightningtipbot/telebot.v2" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" ) -type StateCallbackMessage map[lnbits.UserStateKey]func(ctx context.Context, m *tb.Message) (context.Context, error) +type StateCallbackMessage map[lnbits.UserStateKey]func(ctx intercept.Context) (intercept.Context, error) var stateCallbackMessage StateCallbackMessage diff --git a/internal/telegram/telegram.go b/internal/telegram/telegram.go index 5b1d95d..fc25b2f 100644 --- a/internal/telegram/telegram.go +++ b/internal/telegram/telegram.go @@ -8,7 +8,7 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/rate" "github.com/eko/gocache/store" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) // getChatIdFromRecipient will parse the recipient to int64 diff --git a/internal/telegram/text.go b/internal/telegram/text.go index 2d2c209..37929fc 100644 --- a/internal/telegram/text.go +++ b/internal/telegram/text.go @@ -5,15 +5,17 @@ import ( "encoding/json" "fmt" "github.com/LightningTipBot/LightningTipBot/internal/errors" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "strings" "github.com/LightningTipBot/LightningTipBot/internal/lnbits" "github.com/LightningTipBot/LightningTipBot/pkg/lightning" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) -func (bot *TipBot) anyTextHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) anyTextHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() if m.Chat.Type != tb.ChatPrivate { return ctx, errors.Create(errors.NoPrivateChatError) } @@ -21,7 +23,7 @@ func (bot *TipBot) anyTextHandler(ctx context.Context, m *tb.Message) (context.C // check if user is in Database, if not, initialize wallet user := LoadUser(ctx) if user.Wallet == nil || !user.Initialized { - return bot.startHandler(ctx, m) + return bot.startHandler(ctx) } // check if the user clicked on the balance button @@ -30,21 +32,21 @@ func (bot *TipBot) anyTextHandler(ctx context.Context, m *tb.Message) (context.C // overwrite the message text so it doesn't cause an infinite loop // because balanceHandler calls anyTextHAndler... m.Text = "" - return bot.balanceHandler(ctx, m) + return bot.balanceHandler(ctx) } // could be an invoice anyText := strings.ToLower(m.Text) if lightning.IsInvoice(anyText) { m.Text = "/pay " + anyText - return bot.payHandler(ctx, m) + return bot.payHandler(ctx) } if lightning.IsLnurl(anyText) { m.Text = "/lnurl " + anyText - return bot.lnurlHandler(ctx, m) + return bot.lnurlHandler(ctx) } if c := stateCallbackMessage[user.StateKey]; c != nil { - return c(ctx, m) + return c(ctx) //ResetUserState(user, bot) } return ctx, nil @@ -83,8 +85,9 @@ func (bot *TipBot) askForUser(ctx context.Context, id string, eventType string, // enterAmountHandler is invoked in anyTextHandler when the user needs to enter an amount // the amount is then stored as an entry in the user's stateKey in the user database -// any other handler that relies on this, needs to load the resulting amount from the database -func (bot *TipBot) enterUserHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +// any other ctx that relies on this, needs to load the resulting amount from the database +func (bot *TipBot) enterUserHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() user := LoadUser(ctx) if user.Wallet == nil { return ctx, errors.Create(errors.UserNoWalletError) @@ -114,7 +117,7 @@ func (bot *TipBot) enterUserHandler(ctx context.Context, m *tb.Message) (context switch EnterUserStateData.Type { case "CreateSendState": m.Text = fmt.Sprintf("/send %s", userstr) - return bot.sendHandler(ctx, m) + return bot.sendHandler(ctx) default: ResetUserState(user, bot) return ctx, errors.Create(errors.InvalidSyntaxError) diff --git a/internal/telegram/tip.go b/internal/telegram/tip.go index 21e19fd..c79e9c8 100644 --- a/internal/telegram/tip.go +++ b/internal/telegram/tip.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "github.com/LightningTipBot/LightningTipBot/internal/errors" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" "strings" "time" @@ -12,7 +13,7 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/i18n" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) func helpTipUsage(ctx context.Context, errormsg string) string { @@ -31,9 +32,10 @@ func TipCheckSyntax(ctx context.Context, m *tb.Message) (bool, string) { return true, "" } -func (bot *TipBot) tipHandler(ctx context.Context, m *tb.Message) (context.Context, error) { +func (bot *TipBot) tipHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() // check and print all commands - bot.anyTextHandler(ctx, m) + bot.anyTextHandler(ctx) user := LoadUser(ctx) if user.Wallet == nil { return ctx, fmt.Errorf("user has no wallet") @@ -64,7 +66,7 @@ func (bot *TipBot) tipHandler(ctx context.Context, m *tb.Message) (context.Conte return ctx, errors.Create(errors.InvalidAmountError) } - err = bot.parseCmdDonHandler(ctx, m) + err = bot.parseCmdDonHandler(ctx) if err == nil { return ctx, fmt.Errorf("invalid parseCmdDonHandler") } diff --git a/internal/telegram/tipjar.go b/internal/telegram/tipjar.go index 7abae3b..a9b13dd 100644 --- a/internal/telegram/tipjar.go +++ b/internal/telegram/tipjar.go @@ -6,6 +6,8 @@ import ( "strings" "time" + "github.com/LightningTipBot/LightningTipBot/internal/telegram/intercept" + "github.com/LightningTipBot/LightningTipBot/internal/runtime/mutex" "github.com/LightningTipBot/LightningTipBot/internal/storage" @@ -16,11 +18,11 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/lnbits" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) var ( - inlineTipjarMenu = &tb.ReplyMarkup{ResizeReplyKeyboard: false} + inlineTipjarMenu = &tb.ReplyMarkup{ResizeKeyboard: false} btnCancelInlineTipjar = inlineTipjarMenu.Data("đŸšĢ", "cancel_tipjar_inline") btnAcceptInlineTipjar = inlineTipjarMenu.Data("💸 Pay", "confirm_tipjar_inline") ) @@ -131,28 +133,28 @@ func (bot TipBot) makeTipjar(ctx context.Context, m *tb.Message, query bool) (*I return tipjar, err } -func (bot TipBot) makeQueryTipjar(ctx context.Context, q *tb.Query, query bool) (*InlineTipjar, error) { - tipjar, err := bot.createTipjar(ctx, q.Text, &q.From) +func (bot TipBot) makeQueryTipjar(ctx intercept.Context) (*InlineTipjar, error) { + tipjar, err := bot.createTipjar(ctx, ctx.Query().Text, ctx.Query().Sender) if err != nil { switch err.(errors.TipBotError).Code { case errors.DecodeAmountError: - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineQueryTipjarTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineQueryTipjarTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) return nil, err case errors.DecodePerUserAmountError: - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineQueryTipjarTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineQueryTipjarTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) return nil, err case errors.InvalidAmountError: - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineSendInvalidAmountMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineSendInvalidAmountMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) return nil, err case errors.InvalidAmountPerUserError: - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineTipjarInvalidPeruserAmountMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineTipjarInvalidPeruserAmountMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) return nil, err case errors.GetBalanceError: - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineQueryTipjarTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineQueryTipjarTitle"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) return nil, err case errors.BalanceToLowError: log.Errorf(err.Error()) - bot.inlineQueryReplyWithError(q, TranslateUser(ctx, "inlineSendBalanceLowMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) + bot.inlineQueryReplyWithError(ctx, TranslateUser(ctx, "inlineSendBalanceLowMessage"), fmt.Sprintf(TranslateUser(ctx, "inlineQueryTipjarDescription"), bot.Telegram.Me.Username)) return nil, err } } @@ -160,7 +162,7 @@ func (bot TipBot) makeQueryTipjar(ctx context.Context, q *tb.Query, query bool) } func (bot TipBot) makeTipjarKeyboard(ctx context.Context, inlineTipjar *InlineTipjar) *tb.ReplyMarkup { - inlineTipjarMenu := &tb.ReplyMarkup{ResizeReplyKeyboard: true} + inlineTipjarMenu := &tb.ReplyMarkup{ResizeKeyboard: true} // slice of buttons buttons := make([]tb.Btn, 0) cancelInlineTipjarButton := inlineTipjarMenu.Data(Translate(ctx, "cancelButtonMessage"), "cancel_tipjar_inline", inlineTipjar.ID) @@ -173,13 +175,14 @@ func (bot TipBot) makeTipjarKeyboard(ctx context.Context, inlineTipjar *InlineTi return inlineTipjarMenu } -func (bot TipBot) tipjarHandler(ctx context.Context, m *tb.Message) (context.Context, error) { - bot.anyTextHandler(ctx, m) +func (bot TipBot) tipjarHandler(ctx intercept.Context) (intercept.Context, error) { + m := ctx.Message() + bot.anyTextHandler(ctx) if m.Private() { bot.trySendMessage(m.Sender, fmt.Sprintf(Translate(ctx, "inlineTipjarHelpText"), Translate(ctx, "inlineTipjarHelpTipjarInGroup"))) return ctx, errors.Create(errors.NoPrivateChatError) } - ctx = bot.mapTipjarLanguage(ctx, m.Text) + ctx.Context = bot.mapTipjarLanguage(ctx, m.Text) inlineTipjar, err := bot.makeTipjar(ctx, m, false) if err != nil { log.Errorf("[tipjar] %s", err.Error()) @@ -191,8 +194,9 @@ func (bot TipBot) tipjarHandler(ctx context.Context, m *tb.Message) (context.Con return ctx, inlineTipjar.Set(inlineTipjar, bot.Bunt) } -func (bot TipBot) handleInlineTipjarQuery(ctx context.Context, q *tb.Query) (context.Context, error) { - inlineTipjar, err := bot.makeQueryTipjar(ctx, q, false) +func (bot TipBot) handleInlineTipjarQuery(ctx intercept.Context) (intercept.Context, error) { + q := ctx.Query() + inlineTipjar, err := bot.makeQueryTipjar(ctx) if err != nil { // log.Errorf("[tipjar] %s", err.Error()) return ctx, err @@ -210,7 +214,7 @@ func (bot TipBot) handleInlineTipjarQuery(ctx context.Context, q *tb.Query) (con // required for photos ThumbURL: url, } - result.ReplyMarkup = &tb.InlineKeyboardMarkup{InlineKeyboard: bot.makeTipjarKeyboard(ctx, inlineTipjar).InlineKeyboard} + result.ReplyMarkup = &tb.ReplyMarkup{InlineKeyboard: bot.makeTipjarKeyboard(ctx, inlineTipjar).InlineKeyboard} results[i] = result // needed to set a unique string ID for each result results[i].SetResultID(inlineTipjar.ID) @@ -231,7 +235,8 @@ func (bot TipBot) handleInlineTipjarQuery(ctx context.Context, q *tb.Query) (con return ctx, nil } -func (bot *TipBot) acceptInlineTipjarHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) acceptInlineTipjarHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() from := LoadUser(ctx) if from.Wallet == nil { return ctx, errors.Create(errors.UserNoWalletError) @@ -248,7 +253,7 @@ func (bot *TipBot) acceptInlineTipjarHandler(ctx context.Context, c *tb.Callback to := inlineTipjar.To if !inlineTipjar.Active { log.Errorf(fmt.Sprintf("[tipjar] tipjar %s inactive.", inlineTipjar.ID)) - bot.tryEditMessage(c.Message, i18n.Translate(inlineTipjar.LanguageCode, "inlineTipjarCancelledMessage"), &tb.ReplyMarkup{}) + bot.tryEditMessage(c, i18n.Translate(inlineTipjar.LanguageCode, "inlineTipjarCancelledMessage"), &tb.ReplyMarkup{}) return ctx, errors.Create(errors.NotActiveError) } @@ -314,7 +319,7 @@ func (bot *TipBot) acceptInlineTipjarHandler(ctx context.Context, c *tb.Callback } // update message log.Infoln(inlineTipjar.Message) - bot.tryEditMessage(c.Message, inlineTipjar.Message, bot.makeTipjarKeyboard(ctx, inlineTipjar)) + bot.tryEditMessage(c, inlineTipjar.Message, bot.makeTipjarKeyboard(ctx, inlineTipjar)) } if inlineTipjar.GivenAmount >= inlineTipjar.Amount { // tipjar is full @@ -324,7 +329,7 @@ func (bot *TipBot) acceptInlineTipjarHandler(ctx context.Context, c *tb.Callback inlineTipjar.Amount, inlineTipjar.NGiven, ) - bot.tryEditMessage(c.Message, inlineTipjar.Message) + bot.tryEditMessage(c, inlineTipjar.Message) // send update to tipjar creator if inlineTipjar.Active && inlineTipjar.To.Telegram.ID != 0 { bot.trySendMessage(inlineTipjar.To.Telegram, listTipjarGivers(inlineTipjar)) @@ -335,7 +340,8 @@ func (bot *TipBot) acceptInlineTipjarHandler(ctx context.Context, c *tb.Callback } -func (bot *TipBot) cancelInlineTipjarHandler(ctx context.Context, c *tb.Callback) (context.Context, error) { +func (bot *TipBot) cancelInlineTipjarHandler(ctx intercept.Context) (intercept.Context, error) { + c := ctx.Callback() tx := &InlineTipjar{Base: storage.New(storage.ID(c.Data))} mutex.LockWithContext(ctx, tx.ID) defer mutex.UnlockWithContext(ctx, tx.ID) @@ -348,7 +354,7 @@ func (bot *TipBot) cancelInlineTipjarHandler(ctx context.Context, c *tb.Callback if c.Sender.ID != inlineTipjar.To.Telegram.ID { return ctx, errors.Create(errors.UnknownError) } - bot.tryEditMessage(c.Message, i18n.Translate(inlineTipjar.LanguageCode, "inlineTipjarCancelledMessage"), &tb.ReplyMarkup{}) + bot.tryEditMessage(c, i18n.Translate(inlineTipjar.LanguageCode, "inlineTipjarCancelledMessage"), &tb.ReplyMarkup{}) // send update to tipjar creator if inlineTipjar.Active && inlineTipjar.To.Telegram.ID != 0 { diff --git a/internal/telegram/tooltip.go b/internal/telegram/tooltip.go index 673fcf3..6b43aed 100644 --- a/internal/telegram/tooltip.go +++ b/internal/telegram/tooltip.go @@ -13,7 +13,7 @@ import ( log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) const ( diff --git a/internal/telegram/tooltip_test.go b/internal/telegram/tooltip_test.go index bd4beb8..56f96f6 100644 --- a/internal/telegram/tooltip_test.go +++ b/internal/telegram/tooltip_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) var ( diff --git a/internal/telegram/transaction.go b/internal/telegram/transaction.go index 6493a01..1756fa5 100644 --- a/internal/telegram/transaction.go +++ b/internal/telegram/transaction.go @@ -7,7 +7,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/LightningTipBot/LightningTipBot/internal/lnbits" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" ) type Transaction struct { diff --git a/internal/telegram/users.go b/internal/telegram/users.go index 4d0b6bb..6a8dff9 100644 --- a/internal/telegram/users.go +++ b/internal/telegram/users.go @@ -10,7 +10,7 @@ import ( "github.com/LightningTipBot/LightningTipBot/internal/str" "github.com/eko/gocache/store" log "github.com/sirupsen/logrus" - tb "gopkg.in/lightningtipbot/telebot.v2" + tb "gopkg.in/lightningtipbot/telebot.v3" "gorm.io/gorm" ) diff --git a/main.go b/main.go index d60dd02..06f34f0 100644 --- a/main.go +++ b/main.go @@ -43,12 +43,12 @@ func startApiServer(bot *telegram.TipBot) { // start external api server s := api.NewServer(internal.Configuration.Bot.LNURLServerUrl.Host) - // append lnurl handler functions + // append lnurl ctx functions lnUrl := lnurl.New(bot) s.AppendRoute("/.well-known/lnurlp/{username}", lnUrl.Handle, http.MethodGet) s.AppendRoute("/@{username}", lnUrl.Handle, http.MethodGet) - // append lndhub handler functions + // append lndhub ctx functions hub := lndhub.New(bot) s.AppendRoute(`/lndhub/ext/{.*}`, hub.Handle) s.AppendRoute(`/lndhub/ext`, hub.Handle)