mirror of
https://github.com/idanoo/autobrr
synced 2025-07-22 16:29:12 +00:00
feat: add notifications (#216)
* feat: initial notifications support * chore: update deps
This commit is contained in:
parent
3185832708
commit
431742fd94
20 changed files with 1632 additions and 36 deletions
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/autobrr/autobrr/internal/indexer"
|
||||
"github.com/autobrr/autobrr/internal/irc"
|
||||
"github.com/autobrr/autobrr/internal/logger"
|
||||
"github.com/autobrr/autobrr/internal/notification"
|
||||
"github.com/autobrr/autobrr/internal/release"
|
||||
"github.com/autobrr/autobrr/internal/server"
|
||||
"github.com/autobrr/autobrr/internal/user"
|
||||
|
@ -74,6 +75,7 @@ func main() {
|
|||
filterRepo = database.NewFilterRepo(db)
|
||||
indexerRepo = database.NewIndexerRepo(db)
|
||||
ircRepo = database.NewIrcRepo(db)
|
||||
notificationRepo = database.NewNotificationRepo(db)
|
||||
releaseRepo = database.NewReleaseRepo(db)
|
||||
userRepo = database.NewUserRepo(db)
|
||||
)
|
||||
|
@ -87,17 +89,18 @@ func main() {
|
|||
filterService = filter.NewService(filterRepo, actionRepo, apiService, indexerService)
|
||||
releaseService = release.NewService(releaseRepo, actionService)
|
||||
ircService = irc.NewService(ircRepo, filterService, indexerService, releaseService)
|
||||
notificationService = notification.NewService(notificationRepo)
|
||||
userService = user.NewService(userRepo)
|
||||
authService = auth.NewService(userService)
|
||||
)
|
||||
|
||||
// register event subscribers
|
||||
events.NewSubscribers(bus, releaseService)
|
||||
events.NewSubscribers(bus, notificationService, releaseService)
|
||||
|
||||
errorChannel := make(chan error)
|
||||
|
||||
go func() {
|
||||
httpServer := http.NewServer(cfg, serverEvents, version, commit, date, actionService, authService, downloadClientService, filterService, indexerService, ircService, releaseService)
|
||||
httpServer := http.NewServer(cfg, serverEvents, version, commit, date, actionService, authService, downloadClientService, filterService, indexerService, ircService, notificationService, releaseService)
|
||||
errorChannel <- httpServer.Open()
|
||||
}()
|
||||
|
||||
|
|
7
go.mod
7
go.mod
|
@ -6,6 +6,7 @@ require (
|
|||
github.com/Masterminds/squirrel v1.5.1
|
||||
github.com/anacrolix/torrent v1.11.0
|
||||
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef
|
||||
github.com/containrrr/shoutrrr v0.5.2
|
||||
github.com/dcarbone/zadapters/zstdlog v0.3.1
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/ergochat/irc-go v0.1.0
|
||||
|
@ -34,6 +35,7 @@ require (
|
|||
github.com/anacrolix/missinggo/v2 v2.5.2 // indirect
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fatih/color v1.10.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/gdm85/go-rencode v0.1.8 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
|
@ -45,8 +47,12 @@ require (
|
|||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.2 // indirect
|
||||
github.com/nxadm/tail v1.4.6 // indirect
|
||||
github.com/onsi/ginkgo v1.14.2 // indirect
|
||||
github.com/onsi/gomega v1.10.1 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
|
@ -63,6 +69,7 @@ require (
|
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
|
||||
gopkg.in/ini.v1 v1.64.0 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
lukechampine.com/uint128 v1.2.0 // indirect
|
||||
modernc.org/cc/v3 v3.35.24 // indirect
|
||||
|
|
141
go.sum
141
go.sum
|
@ -58,6 +58,7 @@ github.com/RoaringBitmap/roaring v0.4.21/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06
|
|||
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/agnivade/wasmbrowsertest v0.3.1/go.mod h1:zQt6ZTdl338xxRaMW395qccVE2eQm0SjC/SDz0mPWQI=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
|
@ -126,6 +127,7 @@ github.com/anacrolix/utp v0.0.0-20180219060659-9e0e1d1d0572/go.mod h1:MDwc+vsGEq
|
|||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
|
@ -144,6 +146,12 @@ github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67
|
|||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chromedp/cdproto v0.0.0-20190614062957-d6d2f92b486d/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw=
|
||||
github.com/chromedp/cdproto v0.0.0-20190621002710-8cbd498dd7a0/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw=
|
||||
github.com/chromedp/cdproto v0.0.0-20190812224334-39ef923dcb8d/go.mod h1:0YChpVzuLJC5CPr+x3xkHN6Z8KOSXjNbL7qV8Wc4GW0=
|
||||
github.com/chromedp/cdproto v0.0.0-20190926234355-1b4886c6fad6/go.mod h1:0YChpVzuLJC5CPr+x3xkHN6Z8KOSXjNbL7qV8Wc4GW0=
|
||||
github.com/chromedp/chromedp v0.3.1-0.20190619195644-fd957a4d2901/go.mod h1:mJdvfrVn594N9tfiPecUidF6W5jPRKHymqHfzbobPsM=
|
||||
github.com/chromedp/chromedp v0.4.0/go.mod h1:DC3QUn4mJ24dwjcaGQLoZrhm4X/uPHZ6spDbS2uFhm4=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
|
@ -152,15 +160,25 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
|
|||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/containrrr/shoutrrr v0.5.2 h1:97P+wZDpN2gzBKLt4PDP1ZUTLz+k8AJVs40WOu9NNw8=
|
||||
github.com/containrrr/shoutrrr v0.5.2/go.mod h1:XSU8tOIZ1JG8m6OuPozfGLpj6Ed+S8ZrRJaEodQhbzw=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dcarbone/zadapters/zstdlog v0.3.1 h1:BB2brDbBxH+/Dec96EI3Mb9/LC0aFcnDJm9bVqiJRv0=
|
||||
github.com/dcarbone/zadapters/zstdlog v0.3.1/go.mod h1:/eRABVjBs/8NYkN8LLRkBuQJVc6PFVxdec3WbvgIzoc=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
|
@ -181,9 +199,13 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||
github.com/ergochat/irc-go v0.1.0 h1:jBHUayERH9SiPOWe4ePDWRztBjIQsU/jwLbbGUuiOWM=
|
||||
github.com/ergochat/irc-go v0.1.0/go.mod h1:2vi7KNpIPWnReB5hmLpl92eMywQvuIeIIGdt/FQCph0=
|
||||
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
|
||||
github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/gdm85/go-libdeluge v0.5.5 h1:vQ2wuphJVU8UaVS46gFH6VgpRZjyg9qSsXhxSkWoGcQ=
|
||||
|
@ -193,6 +215,7 @@ github.com/gdm85/go-rencode v0.1.8/go.mod h1:0dr3BuaKzeseY1of6o1KRTGB/Oo7eio+YEy
|
|||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
|
@ -204,18 +227,29 @@ github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIu
|
|||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-interpreter/wagon v0.5.1-0.20190713202023-55a163980b6c/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc=
|
||||
github.com/go-interpreter/wagon v0.6.0/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
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=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
|
@ -244,6 +278,7 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
|||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
|
@ -271,6 +306,7 @@ github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIG
|
|||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190908185732-236ed259b199/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
|
@ -284,7 +320,9 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe
|
|||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
|
@ -300,10 +338,15 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC
|
|||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gosuri/uilive v0.0.0-20170323041506-ac356e6e42cd/go.mod h1:qkLSc0A5EXSP6B04TrN4oQoxqFI7A8XvoXSlJi8cwk8=
|
||||
github.com/gosuri/uilive v0.0.3/go.mod h1:qkLSc0A5EXSP6B04TrN4oQoxqFI7A8XvoXSlJi8cwk8=
|
||||
github.com/gosuri/uiprogress v0.0.0-20170224063937-d0567a9d84a1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0=
|
||||
github.com/gosuri/uiprogress v0.0.1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
||||
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
|
||||
|
@ -337,7 +380,11 @@ github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw
|
|||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jarcoal/httpmock v1.0.4 h1:jp+dy/+nonJE4g4xbVtl9QdrUNbn6/3hDT5R4nDIZnA=
|
||||
github.com/jarcoal/httpmock v1.0.4/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
|
@ -349,9 +396,14 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
|||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307/go.mod h1:BjPj+aVjl9FW/cCGiF3nGh5v+9Gd3VCgBQbod/GlMaQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
|
@ -367,14 +419,25 @@ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtB
|
|||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
|
||||
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lukechampine/stm v0.0.0-20191022212748-05486c32d236/go.mod h1:wTLsd5FC9rts7GkMpsPGk64CIuea+03yaLAp19Jmlg8=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
|
@ -397,6 +460,7 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
|
|||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
|
||||
github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
@ -406,11 +470,24 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
|
|||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.6 h1:11TGpSHY7Esh/i/qnq02Jo5oVrI1Gue8Slbq0ujPZFQ=
|
||||
github.com/nxadm/tail v1.4.6/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=
|
||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
|
||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
|
@ -427,6 +504,7 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr
|
|||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
|
@ -434,19 +512,24 @@ github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:
|
|||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/r3labs/sse/v2 v2.7.2 h1:GUyMTu1EPAVUDPZUSkFWx1fXYXXxH4xAcTAIWSs89ZU=
|
||||
github.com/r3labs/sse/v2 v2.7.2/go.mod h1:hUrYMKfu9WquG9MyI0r6TKiNH+6Sw/QPKm2YbNbU5g8=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
|
@ -459,26 +542,41 @@ github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
|||
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
|
||||
github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
|
||||
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
||||
github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
|
||||
github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk=
|
||||
github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
@ -497,6 +595,9 @@ github.com/syncthing/syncthing v0.14.48-rc.4/go.mod h1:nw3siZwHPA6M8iSfjDCWQ402e
|
|||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/twitchyliquid64/golang-asm v0.0.0-20190126203739-365674df15fc/go.mod h1:NoCfSFWosfqMqmmD7hApkirIK9ozpHjxRnRxs1l413A=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
|
@ -504,6 +605,8 @@ github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPyS
|
|||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/willf/bloom v0.0.0-20170505221640-54e3b963ee16/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8=
|
||||
github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
@ -511,6 +614,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
|||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.coder.com/go-tools v0.0.0-20190317003359-0c6a35b74a16/go.mod h1:iKV5yK9t+J5nG9O3uF6KYdPEz3dyfMyB15MN1rbQ8Qw=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
|
@ -525,9 +630,13 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
@ -583,7 +692,9 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r
|
|||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -592,6 +703,7 @@ golang.org/x/net v0.0.0-20190318221613-d196dffd7c2b/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
|
@ -610,6 +722,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
|
|||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
|
@ -658,27 +771,34 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190306220234-b354f8bf4d9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190618155005-516e3c20635f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191126131656-8a8471f7e56d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -697,6 +817,7 @@ golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -705,6 +826,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -747,6 +869,7 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
|
|||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -754,6 +877,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
|
|||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
|
@ -764,6 +888,7 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
@ -902,6 +1027,7 @@ google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEc
|
|||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
|
@ -938,7 +1064,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
|
||||
|
@ -948,14 +1076,20 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR
|
|||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.64.0 h1:Mj2zXEXcNb5joEiSA0zc3HZpTst/iyjNiR4CN8tDzOg=
|
||||
gopkg.in/ini.v1 v1.64.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
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/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/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -963,11 +1097,15 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gosrc.io/xmpp v0.5.1/go.mod h1:L3NFMqYOxyLz3JGmgFyWf7r9htE91zVGiK40oW4RwdY=
|
||||
gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
@ -1116,6 +1254,9 @@ modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
|
|||
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
modernc.org/z v1.3.2 h1:4GWBVMa48UDC7KQ9tnaggN/yTlXg+CdCX9bhgHPQ9AM=
|
||||
modernc.org/z v1.3.2/go.mod h1:PEU2oK2OEA1CfzDTd+8E908qEXhC9s0MfyKp5LZsd+k=
|
||||
mvdan.cc/sh v2.6.4+incompatible/go.mod h1:IeeQbZq+x2SUGBensq/jge5lLQbS3XT2ktyp3wrt4x8=
|
||||
nhooyr.io/websocket v1.6.5/go.mod h1:F259lAzPRAH0htX2y3ehpJe09ih1aSHN7udWki1defY=
|
||||
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
@ -157,26 +157,37 @@ func (s *service) runAction(action domain.Action, release domain.Release) error
|
|||
return nil
|
||||
}
|
||||
|
||||
if rejections != nil {
|
||||
s.bus.Publish("release:push-rejected", &domain.ReleaseActionStatus{
|
||||
ReleaseID: release.ID,
|
||||
Status: domain.ReleasePushStatusRejected,
|
||||
Action: action.Name,
|
||||
Type: action.Type,
|
||||
Rejections: rejections,
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
s.bus.Publish("release:push-approved", &domain.ReleaseActionStatus{
|
||||
rlsActionStatus := &domain.ReleaseActionStatus{
|
||||
ReleaseID: release.ID,
|
||||
Status: domain.ReleasePushStatusApproved,
|
||||
Action: action.Name,
|
||||
Type: action.Type,
|
||||
Rejections: []string{},
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
if rejections != nil {
|
||||
rlsActionStatus.Status = domain.ReleasePushStatusRejected
|
||||
rlsActionStatus.Rejections = rejections
|
||||
}
|
||||
|
||||
// send event for actions
|
||||
s.bus.Publish("release:push", rlsActionStatus)
|
||||
|
||||
// send separate event for notifications
|
||||
s.bus.Publish("events:release:push", &domain.EventsReleasePushed{
|
||||
ReleaseName: release.TorrentName,
|
||||
Filter: release.Filter.Name,
|
||||
Indexer: release.Indexer,
|
||||
InfoHash: release.TorrentHash,
|
||||
Size: release.Size,
|
||||
Status: domain.ReleasePushStatusApproved,
|
||||
Action: action.Name,
|
||||
ActionType: action.Type,
|
||||
Rejections: []string{},
|
||||
Protocol: domain.ReleaseProtocolTorrent,
|
||||
Implementation: domain.ReleaseImplementationIRC,
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
|
||||
return nil
|
||||
|
|
|
@ -218,6 +218,29 @@ CREATE TABLE release_action_status
|
|||
release_id INTEGER NOT NULL,
|
||||
FOREIGN KEY (release_id) REFERENCES "release"(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE notification
|
||||
(
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT,
|
||||
type TEXT,
|
||||
enabled BOOLEAN,
|
||||
events TEXT [] DEFAULT '{}' NOT NULL,
|
||||
token TEXT,
|
||||
api_key TEXT,
|
||||
webhook TEXT,
|
||||
title TEXT,
|
||||
icon TEXT,
|
||||
host TEXT,
|
||||
username TEXT,
|
||||
password TEXT,
|
||||
channel TEXT,
|
||||
rooms TEXT,
|
||||
targets TEXT,
|
||||
devices TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`
|
||||
|
||||
var sqliteMigrations = []string{
|
||||
|
@ -488,6 +511,30 @@ DROP TABLE release_action_status;
|
|||
ALTER TABLE release_action_status_dg_tmp
|
||||
RENAME TO release_action_status;
|
||||
`,
|
||||
`
|
||||
CREATE TABLE notification
|
||||
(
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT,
|
||||
type TEXT,
|
||||
enabled BOOLEAN,
|
||||
events TEXT [] DEFAULT '{}' NOT NULL,
|
||||
token TEXT,
|
||||
api_key TEXT,
|
||||
webhook TEXT,
|
||||
title TEXT,
|
||||
icon TEXT,
|
||||
host TEXT,
|
||||
username TEXT,
|
||||
password TEXT,
|
||||
channel TEXT,
|
||||
rooms TEXT,
|
||||
targets TEXT,
|
||||
devices TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`,
|
||||
}
|
||||
|
||||
const postgresSchema = `
|
||||
|
@ -708,8 +755,55 @@ CREATE TABLE release_action_status
|
|||
release_id INTEGER NOT NULL,
|
||||
FOREIGN KEY (release_id) REFERENCES "release"(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE notification
|
||||
(
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT,
|
||||
type TEXT,
|
||||
enabled BOOLEAN,
|
||||
events TEXT [] DEFAULT '{}' NOT NULL,
|
||||
token TEXT,
|
||||
api_key TEXT,
|
||||
webhook TEXT,
|
||||
title TEXT,
|
||||
icon TEXT,
|
||||
host TEXT,
|
||||
username TEXT,
|
||||
password TEXT,
|
||||
channel TEXT,
|
||||
rooms TEXT,
|
||||
targets TEXT,
|
||||
devices TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`
|
||||
|
||||
var postgresMigrations = []string{
|
||||
"",
|
||||
`
|
||||
CREATE TABLE notification
|
||||
(
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT,
|
||||
type TEXT,
|
||||
enabled BOOLEAN,
|
||||
events TEXT [] DEFAULT '{}' NOT NULL,
|
||||
token TEXT,
|
||||
api_key TEXT,
|
||||
webhook TEXT,
|
||||
title TEXT,
|
||||
icon TEXT,
|
||||
host TEXT,
|
||||
username TEXT,
|
||||
password TEXT,
|
||||
channel TEXT,
|
||||
rooms TEXT,
|
||||
targets TEXT,
|
||||
devices TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`,
|
||||
}
|
||||
|
|
266
internal/database/notification.go
Normal file
266
internal/database/notification.go
Normal file
|
@ -0,0 +1,266 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"github.com/autobrr/autobrr/internal/domain"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/lib/pq"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type NotificationRepo struct {
|
||||
db *DB
|
||||
}
|
||||
|
||||
func NewNotificationRepo(db *DB) domain.NotificationRepo {
|
||||
return &NotificationRepo{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *NotificationRepo) Find(ctx context.Context, params domain.NotificationQueryParams) ([]domain.Notification, int, error) {
|
||||
|
||||
queryBuilder := r.db.squirrel.
|
||||
Select("id", "name", "type", "enabled", "events", "webhook", "created_at", "updated_at", "COUNT(*) OVER() AS total_count").
|
||||
From("notification").
|
||||
OrderBy("name")
|
||||
|
||||
query, args, err := queryBuilder.ToSql()
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("notification.find: error building query")
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
rows, err := r.db.handler.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("notification.find: error executing query")
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
notifications := make([]domain.Notification, 0)
|
||||
totalCount := 0
|
||||
for rows.Next() {
|
||||
var n domain.Notification
|
||||
|
||||
var webhook sql.NullString
|
||||
//var token, apiKey, webhook, title, icon, host, username, password, channel, targets, devices sql.NullString
|
||||
//if err := rows.Scan(&n.ID, &n.Name, &n.Type, &n.Enabled, pq.Array(&n.Events), &token, &apiKey, &webhook, &title, &icon, &host, &username, &password, &channel, &targets, &devices, &n.CreatedAt, &n.UpdatedAt); err != nil {
|
||||
//var token, apiKey, webhook, title, icon, host, username, password, channel, targets, devices sql.NullString
|
||||
if err := rows.Scan(&n.ID, &n.Name, &n.Type, &n.Enabled, pq.Array(&n.Events), &webhook, &n.CreatedAt, &n.UpdatedAt, &totalCount); err != nil {
|
||||
log.Error().Stack().Err(err).Msg("notification.find: error scanning row")
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
//n.Token = token.String
|
||||
//n.APIKey = apiKey.String
|
||||
n.Webhook = webhook.String
|
||||
//n.Title = title.String
|
||||
//n.Icon = icon.String
|
||||
//n.Host = host.String
|
||||
//n.Username = username.String
|
||||
//n.Password = password.String
|
||||
//n.Channel = channel.String
|
||||
//n.Targets = targets.String
|
||||
//n.Devices = devices.String
|
||||
|
||||
notifications = append(notifications, n)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return notifications, totalCount, nil
|
||||
}
|
||||
|
||||
func (r *NotificationRepo) List(ctx context.Context) ([]domain.Notification, error) {
|
||||
|
||||
//queryBuilder := r.db.squirrel.
|
||||
// Select("r.id", "r.filter_status", "r.rejections", "r.indexer", "r.filter", "r.protocol", "r.title", "r.torrent_name", "r.size", "r.timestamp", "COUNT(*) OVER() AS total_count").
|
||||
// From("release r").
|
||||
// OrderBy("r.timestamp DESC")
|
||||
//
|
||||
//query, args, err := queryBuilder.ToSql()
|
||||
|
||||
rows, err := r.db.handler.QueryContext(ctx, "SELECT id, name, type, enabled, events, token, api_key, webhook, title, icon, host, username, password, channel, targets, devices, created_at, updated_at FROM notification ORDER BY name ASC")
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("filters_list: error query data")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
var notifications []domain.Notification
|
||||
for rows.Next() {
|
||||
var n domain.Notification
|
||||
//var eventsSlice []string
|
||||
|
||||
var token, apiKey, webhook, title, icon, host, username, password, channel, targets, devices sql.NullString
|
||||
if err := rows.Scan(&n.ID, &n.Name, &n.Type, &n.Enabled, pq.Array(&n.Events), &token, &apiKey, &webhook, &title, &icon, &host, &username, &password, &channel, &targets, &devices, &n.CreatedAt, &n.UpdatedAt); err != nil {
|
||||
log.Error().Stack().Err(err).Msg("notification_list: error scanning data to struct")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//n.Events = ([]domain.NotificationEvent)(eventsSlice)
|
||||
n.Token = token.String
|
||||
n.APIKey = apiKey.String
|
||||
n.Webhook = webhook.String
|
||||
n.Title = title.String
|
||||
n.Icon = icon.String
|
||||
n.Host = host.String
|
||||
n.Username = username.String
|
||||
n.Password = password.String
|
||||
n.Channel = channel.String
|
||||
n.Targets = targets.String
|
||||
n.Devices = devices.String
|
||||
|
||||
notifications = append(notifications, n)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return notifications, nil
|
||||
}
|
||||
|
||||
func (r *NotificationRepo) FindByID(ctx context.Context, id int) (*domain.Notification, error) {
|
||||
|
||||
queryBuilder := r.db.squirrel.
|
||||
Select(
|
||||
"id",
|
||||
"name",
|
||||
"type",
|
||||
"enabled",
|
||||
"events",
|
||||
"token",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
).
|
||||
From("notification").
|
||||
Where("id = ?", id)
|
||||
|
||||
query, args, err := queryBuilder.ToSql()
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("notification.findByID: error building query")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//row := r.db.handler.QueryRowContext(ctx, "SELECT id, name, type, enabled, events, token, api_key, webhook, title, icon, host, username, password, channel, targets, devices, created_at, updated_at FROM notification WHERE id = ?", id)
|
||||
row := r.db.handler.QueryRowContext(ctx, query, args...)
|
||||
if err := row.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var n domain.Notification
|
||||
|
||||
var token, apiKey, webhook, title, icon, host, username, password, channel, targets, devices sql.NullString
|
||||
if err := row.Scan(&n.ID, &n.Name, &n.Type, &n.Enabled, pq.Array(&n.Events), &token, &apiKey, &webhook, &title, &icon, &host, &username, &password, &channel, &targets, &devices, &n.CreatedAt, &n.UpdatedAt); err != nil {
|
||||
log.Error().Stack().Err(err).Msg("notification.findByID: error scanning row")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n.Token = token.String
|
||||
n.APIKey = apiKey.String
|
||||
n.Webhook = webhook.String
|
||||
n.Title = title.String
|
||||
n.Icon = icon.String
|
||||
n.Host = host.String
|
||||
n.Username = username.String
|
||||
n.Password = password.String
|
||||
n.Channel = channel.String
|
||||
n.Targets = targets.String
|
||||
n.Devices = devices.String
|
||||
|
||||
return &n, nil
|
||||
}
|
||||
|
||||
func (r *NotificationRepo) Store(ctx context.Context, notification domain.Notification) (*domain.Notification, error) {
|
||||
webhook := toNullString(notification.Webhook)
|
||||
|
||||
queryBuilder := r.db.squirrel.
|
||||
Insert("notification").
|
||||
Columns(
|
||||
"name",
|
||||
"type",
|
||||
"enabled",
|
||||
"events",
|
||||
"webhook",
|
||||
).
|
||||
Values(
|
||||
notification.Name,
|
||||
notification.Type,
|
||||
notification.Enabled,
|
||||
pq.Array(notification.Events),
|
||||
webhook,
|
||||
).
|
||||
Suffix("RETURNING id").RunWith(r.db.handler)
|
||||
|
||||
// return values
|
||||
var retID int64
|
||||
|
||||
err := queryBuilder.QueryRowContext(ctx).Scan(&retID)
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("notification.store: error executing query")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug().Msgf("notification.store: added new %v", retID)
|
||||
notification.ID = int(retID)
|
||||
|
||||
return ¬ification, nil
|
||||
}
|
||||
|
||||
func (r *NotificationRepo) Update(ctx context.Context, notification domain.Notification) (*domain.Notification, error) {
|
||||
webhook := toNullString(notification.Webhook)
|
||||
|
||||
queryBuilder := r.db.squirrel.
|
||||
Update("notification").
|
||||
Set("name", notification.Name).
|
||||
Set("type", notification.Type).
|
||||
Set("enabled", notification.Enabled).
|
||||
Set("events", pq.Array(notification.Events)).
|
||||
Set("webhook", webhook).
|
||||
Set("updated_at", sq.Expr("CURRENT_TIMESTAMP")).
|
||||
Where("id = ?", notification.ID)
|
||||
|
||||
query, args, err := queryBuilder.ToSql()
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("action.update: error building query")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("notification.update: error executing query")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug().Msgf("notification.update: %v", notification.Name)
|
||||
|
||||
return ¬ification, nil
|
||||
}
|
||||
|
||||
func (r *NotificationRepo) Delete(ctx context.Context, notificationID int) error {
|
||||
queryBuilder := r.db.squirrel.
|
||||
Delete("notification").
|
||||
Where("id = ?", notificationID)
|
||||
|
||||
query, args, err := queryBuilder.ToSql()
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("notification.delete: error building query")
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("notification.delete: error executing query")
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Msgf("notification.delete: successfully deleted: %v", notificationID)
|
||||
|
||||
return nil
|
||||
}
|
18
internal/domain/event.go
Normal file
18
internal/domain/event.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type EventsReleasePushed struct {
|
||||
ReleaseName string
|
||||
Filter string
|
||||
Indexer string
|
||||
InfoHash string
|
||||
Size uint64
|
||||
Status ReleasePushStatus
|
||||
Action string
|
||||
ActionType ActionType
|
||||
Rejections []string
|
||||
Protocol ReleaseProtocol // torrent
|
||||
Implementation ReleaseImplementation // irc, rss, api
|
||||
Timestamp time.Time
|
||||
}
|
75
internal/domain/notification.go
Normal file
75
internal/domain/notification.go
Normal file
|
@ -0,0 +1,75 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NotificationRepo interface {
|
||||
List(ctx context.Context) ([]Notification, error)
|
||||
//FindByType(ctx context.Context, nType NotificationType) ([]Notification, error)
|
||||
Find(ctx context.Context, params NotificationQueryParams) ([]Notification, int, error)
|
||||
FindByID(ctx context.Context, id int) (*Notification, error)
|
||||
Store(ctx context.Context, notification Notification) (*Notification, error)
|
||||
Update(ctx context.Context, notification Notification) (*Notification, error)
|
||||
Delete(ctx context.Context, notificationID int) error
|
||||
}
|
||||
|
||||
type Notification struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type NotificationType `json:"type"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Events []string `json:"events"`
|
||||
Token string `json:"token"`
|
||||
APIKey string `json:"api_key"`
|
||||
Webhook string `json:"webhook"`
|
||||
Title string `json:"title"`
|
||||
Icon string `json:"icon"`
|
||||
Username string `json:"username"`
|
||||
Host string `json:"host"`
|
||||
Password string `json:"password"`
|
||||
Channel string `json:"channel"`
|
||||
Rooms string `json:"rooms"`
|
||||
Targets string `json:"targets"`
|
||||
Devices string `json:"devices"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type NotificationType string
|
||||
|
||||
const (
|
||||
NotificationTypeDiscord NotificationType = "DISCORD"
|
||||
NotificationTypeIFTTT NotificationType = "IFTTT"
|
||||
NotificationTypeJoin NotificationType = "JOIN"
|
||||
NotificationTypeMattermost NotificationType = "MATTERMOST"
|
||||
NotificationTypeMatrix NotificationType = "MATRIX"
|
||||
NotificationTypePushBullet NotificationType = "PUSH_BULLET"
|
||||
NotificationTypePushover NotificationType = "PUSHOVER"
|
||||
NotificationTypeRocketChat NotificationType = "ROCKETCHAT"
|
||||
NotificationTypeSlack NotificationType = "SLACK"
|
||||
NotificationTypeTelegram NotificationType = "TELEGRAM"
|
||||
)
|
||||
|
||||
type NotificationEvent string
|
||||
|
||||
const (
|
||||
NotificationEventPushApproved NotificationEvent = "PUSH_APPROVED"
|
||||
NotificationEventPushRejected NotificationEvent = "PUSH_REJECTED"
|
||||
NotificationEventUpdateAvailable NotificationEvent = "UPDATE_AVAILABLE"
|
||||
NotificationEventIRCHealth NotificationEvent = "IRC_HEALTH"
|
||||
)
|
||||
|
||||
type NotificationEventArr []NotificationEvent
|
||||
|
||||
type NotificationQueryParams struct {
|
||||
Limit uint64
|
||||
Offset uint64
|
||||
Sort map[string]string
|
||||
Filters struct {
|
||||
Indexers []string
|
||||
PushStatus string
|
||||
}
|
||||
Search string
|
||||
}
|
|
@ -1501,6 +1501,19 @@ const (
|
|||
ReleasePushStatusPending ReleasePushStatus = "PENDING" // Initial status
|
||||
)
|
||||
|
||||
func (r ReleasePushStatus) String() string {
|
||||
switch r {
|
||||
case ReleasePushStatusApproved:
|
||||
return "Approved"
|
||||
case ReleasePushStatusRejected:
|
||||
return "Rejected"
|
||||
case ReleasePushStatusErr:
|
||||
return "Error"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
type ReleaseFilterStatus string
|
||||
|
||||
const (
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/autobrr/autobrr/internal/domain"
|
||||
"github.com/autobrr/autobrr/internal/notification"
|
||||
"github.com/autobrr/autobrr/internal/release"
|
||||
|
||||
"github.com/asaskevich/EventBus"
|
||||
|
@ -11,12 +12,17 @@ import (
|
|||
)
|
||||
|
||||
type Subscriber struct {
|
||||
eventbus EventBus.Bus
|
||||
releaseSvc release.Service
|
||||
eventbus EventBus.Bus
|
||||
notificationSvc notification.Service
|
||||
releaseSvc release.Service
|
||||
}
|
||||
|
||||
func NewSubscribers(eventbus EventBus.Bus, releaseSvc release.Service) Subscriber {
|
||||
s := Subscriber{eventbus: eventbus, releaseSvc: releaseSvc}
|
||||
func NewSubscribers(eventbus EventBus.Bus, notificationSvc notification.Service, releaseSvc release.Service) Subscriber {
|
||||
s := Subscriber{
|
||||
eventbus: eventbus,
|
||||
notificationSvc: notificationSvc,
|
||||
releaseSvc: releaseSvc,
|
||||
}
|
||||
|
||||
s.Register()
|
||||
|
||||
|
@ -25,8 +31,8 @@ func NewSubscribers(eventbus EventBus.Bus, releaseSvc release.Service) Subscribe
|
|||
|
||||
func (s Subscriber) Register() {
|
||||
s.eventbus.Subscribe("release:store-action-status", s.releaseActionStatus)
|
||||
s.eventbus.Subscribe("release:push-rejected", s.releasePushRejected)
|
||||
s.eventbus.Subscribe("release:push-approved", s.releasePushApproved)
|
||||
s.eventbus.Subscribe("release:push", s.releasePushStatus)
|
||||
s.eventbus.Subscribe("events:release:push", s.releasePush)
|
||||
}
|
||||
|
||||
func (s Subscriber) releaseActionStatus(actionStatus *domain.ReleaseActionStatus) {
|
||||
|
@ -38,20 +44,18 @@ func (s Subscriber) releaseActionStatus(actionStatus *domain.ReleaseActionStatus
|
|||
}
|
||||
}
|
||||
|
||||
func (s Subscriber) releasePushRejected(actionStatus *domain.ReleaseActionStatus) {
|
||||
log.Trace().Msgf("events: 'release:push-rejected' '%+v'", actionStatus)
|
||||
func (s Subscriber) releasePushStatus(actionStatus *domain.ReleaseActionStatus) {
|
||||
log.Trace().Msgf("events: 'release:push' '%+v'", actionStatus)
|
||||
|
||||
err := s.releaseSvc.StoreReleaseActionStatus(context.Background(), actionStatus)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("events: 'release:push-rejected' error")
|
||||
if err := s.releaseSvc.StoreReleaseActionStatus(context.Background(), actionStatus); err != nil {
|
||||
log.Error().Err(err).Msgf("events: 'release:push' error")
|
||||
}
|
||||
}
|
||||
|
||||
func (s Subscriber) releasePushApproved(actionStatus *domain.ReleaseActionStatus) {
|
||||
log.Trace().Msgf("events: 'release:push-approved' '%+v'", actionStatus)
|
||||
func (s Subscriber) releasePush(event *domain.EventsReleasePushed) {
|
||||
log.Trace().Msgf("events: 'events:release:push' '%+v'", event)
|
||||
|
||||
err := s.releaseSvc.StoreReleaseActionStatus(context.Background(), actionStatus)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("events: 'release:push-approved' error")
|
||||
if err := s.notificationSvc.SendEvent(*event); err != nil {
|
||||
log.Error().Err(err).Msgf("events: 'events:release:push' error sending notification")
|
||||
}
|
||||
}
|
||||
|
|
106
internal/http/notification.go
Normal file
106
internal/http/notification.go
Normal file
|
@ -0,0 +1,106 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/autobrr/autobrr/internal/domain"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
type notificationService interface {
|
||||
Find(context.Context, domain.NotificationQueryParams) ([]domain.Notification, int, error)
|
||||
FindByID(ctx context.Context, id int) (*domain.Notification, error)
|
||||
Store(ctx context.Context, n domain.Notification) (*domain.Notification, error)
|
||||
Update(ctx context.Context, n domain.Notification) (*domain.Notification, error)
|
||||
Delete(ctx context.Context, id int) error
|
||||
}
|
||||
|
||||
type notificationHandler struct {
|
||||
encoder encoder
|
||||
service notificationService
|
||||
}
|
||||
|
||||
func newNotificationHandler(encoder encoder, service notificationService) *notificationHandler {
|
||||
return ¬ificationHandler{
|
||||
encoder: encoder,
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
|
||||
func (h notificationHandler) Routes(r chi.Router) {
|
||||
r.Get("/", h.list)
|
||||
r.Post("/", h.store)
|
||||
r.Put("/{notificationID}", h.update)
|
||||
r.Delete("/{notificationID}", h.delete)
|
||||
}
|
||||
|
||||
func (h notificationHandler) list(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
list, _, err := h.service.Find(ctx, domain.NotificationQueryParams{})
|
||||
if err != nil {
|
||||
h.encoder.StatusNotFound(ctx, w)
|
||||
return
|
||||
}
|
||||
|
||||
h.encoder.StatusResponse(ctx, w, list, http.StatusOK)
|
||||
}
|
||||
|
||||
func (h notificationHandler) store(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
data domain.Notification
|
||||
)
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
||||
// encode error
|
||||
return
|
||||
}
|
||||
|
||||
filter, err := h.service.Store(ctx, data)
|
||||
if err != nil {
|
||||
// encode error
|
||||
return
|
||||
}
|
||||
|
||||
h.encoder.StatusResponse(ctx, w, filter, http.StatusCreated)
|
||||
}
|
||||
|
||||
func (h notificationHandler) update(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
data domain.Notification
|
||||
)
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
||||
// encode error
|
||||
return
|
||||
}
|
||||
|
||||
filter, err := h.service.Update(ctx, data)
|
||||
if err != nil {
|
||||
// encode error
|
||||
return
|
||||
}
|
||||
|
||||
h.encoder.StatusResponse(ctx, w, filter, http.StatusOK)
|
||||
}
|
||||
|
||||
func (h notificationHandler) delete(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
notificationID = chi.URLParam(r, "notificationID")
|
||||
)
|
||||
|
||||
id, _ := strconv.Atoi(notificationID)
|
||||
|
||||
if err := h.service.Delete(ctx, id); err != nil {
|
||||
// return err
|
||||
}
|
||||
|
||||
h.encoder.StatusResponse(ctx, w, nil, http.StatusNoContent)
|
||||
}
|
|
@ -31,10 +31,11 @@ type Server struct {
|
|||
filterService filterService
|
||||
indexerService indexerService
|
||||
ircService ircService
|
||||
notificationService notificationService
|
||||
releaseService releaseService
|
||||
}
|
||||
|
||||
func NewServer(config domain.Config, sse *sse.Server, version string, commit string, date string, actionService actionService, authService authService, downloadClientSvc downloadClientService, filterSvc filterService, indexerSvc indexerService, ircSvc ircService, releaseSvc releaseService) Server {
|
||||
func NewServer(config domain.Config, sse *sse.Server, version string, commit string, date string, actionService actionService, authService authService, downloadClientSvc downloadClientService, filterSvc filterService, indexerSvc indexerService, ircSvc ircService, notificationSvc notificationService, releaseSvc releaseService) Server {
|
||||
return Server{
|
||||
config: config,
|
||||
sse: sse,
|
||||
|
@ -50,6 +51,7 @@ func NewServer(config domain.Config, sse *sse.Server, version string, commit str
|
|||
filterService: filterSvc,
|
||||
indexerService: indexerSvc,
|
||||
ircService: ircSvc,
|
||||
notificationService: notificationSvc,
|
||||
releaseService: releaseSvc,
|
||||
}
|
||||
}
|
||||
|
@ -107,6 +109,7 @@ func (s Server) Handler() http.Handler {
|
|||
r.Route("/filters", newFilterHandler(encoder, s.filterService).Routes)
|
||||
r.Route("/irc", newIrcHandler(encoder, s.ircService).Routes)
|
||||
r.Route("/indexer", newIndexerHandler(encoder, s.indexerService, s.ircService).Routes)
|
||||
r.Route("/notification", newNotificationHandler(encoder, s.notificationService).Routes)
|
||||
r.Route("/release", newReleaseHandler(encoder, s.releaseService).Routes)
|
||||
|
||||
r.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
104
internal/notification/discord.go
Normal file
104
internal/notification/discord.go
Normal file
|
@ -0,0 +1,104 @@
|
|||
package notification
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/autobrr/autobrr/internal/domain"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type DiscordMessage struct {
|
||||
Content interface{} `json:"content"`
|
||||
Embeds []DiscordEmbeds `json:"embeds"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
type DiscordEmbeds struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Color int `json:"color"`
|
||||
Fields []DiscordEmbedsFields `json:"fields"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
type DiscordEmbedsFields struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Inline bool `json:"inline,omitempty"`
|
||||
}
|
||||
|
||||
func discordNotification(event domain.EventsReleasePushed, webhookURL string) {
|
||||
t := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
|
||||
client := http.Client{Transport: t, Timeout: 15 * time.Second}
|
||||
|
||||
m := DiscordMessage{
|
||||
Content: nil,
|
||||
Embeds: []DiscordEmbeds{
|
||||
{
|
||||
Title: event.ReleaseName,
|
||||
Description: "New release!",
|
||||
Color: 5814783,
|
||||
Fields: []DiscordEmbedsFields{
|
||||
{
|
||||
Name: "Status",
|
||||
Value: event.Status.String(),
|
||||
Inline: true,
|
||||
},
|
||||
{
|
||||
Name: "Indexer",
|
||||
Value: event.Indexer,
|
||||
Inline: true,
|
||||
},
|
||||
{
|
||||
Name: "Filter",
|
||||
Value: event.Filter,
|
||||
Inline: true,
|
||||
},
|
||||
{
|
||||
Name: "Action",
|
||||
Value: event.Action,
|
||||
Inline: false,
|
||||
},
|
||||
},
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
},
|
||||
Username: "brr",
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("discord client could not marshal data: %v", m)
|
||||
return
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, webhookURL, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
//log.Error().Err(err).Msgf("webhook client request error: %v", action.WebhookHost)
|
||||
return
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
//req.Header.Set("User-Agent", "autobrr")
|
||||
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
//log.Error().Err(err).Msgf("webhook client request error: %v", action.WebhookHost)
|
||||
return
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
|
||||
log.Debug().Msg("notification successfully sent to discord")
|
||||
|
||||
return
|
||||
}
|
145
internal/notification/service.go
Normal file
145
internal/notification/service.go
Normal file
|
@ -0,0 +1,145 @@
|
|||
package notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/autobrr/autobrr/internal/domain"
|
||||
"github.com/containrrr/shoutrrr"
|
||||
t "github.com/containrrr/shoutrrr/pkg/types"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
Find(ctx context.Context, params domain.NotificationQueryParams) ([]domain.Notification, int, error)
|
||||
FindByID(ctx context.Context, id int) (*domain.Notification, error)
|
||||
Store(ctx context.Context, n domain.Notification) (*domain.Notification, error)
|
||||
Update(ctx context.Context, n domain.Notification) (*domain.Notification, error)
|
||||
Delete(ctx context.Context, id int) error
|
||||
Send(event domain.NotificationEvent, msg string) error
|
||||
SendEvent(event domain.EventsReleasePushed) error
|
||||
}
|
||||
|
||||
type service struct {
|
||||
repo domain.NotificationRepo
|
||||
}
|
||||
|
||||
func NewService(repo domain.NotificationRepo) Service {
|
||||
return &service{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) Find(ctx context.Context, params domain.NotificationQueryParams) ([]domain.Notification, int, error) {
|
||||
return s.repo.Find(ctx, params)
|
||||
}
|
||||
|
||||
func (s *service) FindByID(ctx context.Context, id int) (*domain.Notification, error) {
|
||||
return s.repo.FindByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *service) Store(ctx context.Context, n domain.Notification) (*domain.Notification, error) {
|
||||
return s.repo.Store(ctx, n)
|
||||
}
|
||||
|
||||
func (s *service) Update(ctx context.Context, n domain.Notification) (*domain.Notification, error) {
|
||||
return s.repo.Update(ctx, n)
|
||||
}
|
||||
|
||||
func (s *service) Delete(ctx context.Context, id int) error {
|
||||
return s.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
// Send notifications
|
||||
func (s *service) Send(event domain.NotificationEvent, msg string) error {
|
||||
// find notifications for type X
|
||||
|
||||
notifications, err := s.repo.List(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var urls []string
|
||||
|
||||
for _, n := range notifications {
|
||||
if !n.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
switch n.Type {
|
||||
case domain.NotificationTypeDiscord:
|
||||
urls = append(urls, fmt.Sprintf("discord://%v@%v", n.Token, n.Webhook))
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(urls) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
sender, err := shoutrrr.CreateSender(urls...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := t.Params{"title": "TEST"}
|
||||
items := []t.MessageItem{
|
||||
{
|
||||
Text: "text hello",
|
||||
Fields: []t.Field{
|
||||
{
|
||||
Key: "eventt",
|
||||
Value: "push?",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
//items = append(items, t.MessageItem{
|
||||
// Text: "text hello",
|
||||
// Fields: []t.Field{
|
||||
// {
|
||||
// Key: "eventt",
|
||||
// Value: "push?",
|
||||
// },
|
||||
// },
|
||||
//})
|
||||
|
||||
sender.SendItems(items, p)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) SendEvent(event domain.EventsReleasePushed) error {
|
||||
notifications, err := s.repo.List(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.send(notifications, event)
|
||||
}
|
||||
|
||||
func (s *service) send(notifications []domain.Notification, event domain.EventsReleasePushed) error {
|
||||
// find notifications for type X
|
||||
for _, n := range notifications {
|
||||
if !n.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
if n.Events == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, evt := range n.Events {
|
||||
if evt == string(event.Status) {
|
||||
switch n.Type {
|
||||
case domain.NotificationTypeDiscord:
|
||||
go discordNotification(event, n.Webhook)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -108,6 +108,12 @@ export const APIClient = {
|
|||
events: {
|
||||
logs: () => new EventSource(`${sseBaseUrl()}api/events?stream=logs`, { withCredentials: true })
|
||||
},
|
||||
notifications: {
|
||||
getAll: () => appClient.Get<Notification[]>("api/notification"),
|
||||
create: (notification: Notification) => appClient.Post("api/notification", notification),
|
||||
update: (notification: Notification) => appClient.Put(`api/notification/${notification.id}`, notification),
|
||||
delete: (id: number) => appClient.Delete(`api/notification/${id}`),
|
||||
},
|
||||
release: {
|
||||
find: (query?: string) => appClient.Get<ReleaseFindResponse>(`api/release${query}`),
|
||||
findQuery: (offset?: number, limit?: number, filters?: Array<ReleaseFilter>) => {
|
||||
|
|
|
@ -227,4 +227,35 @@ export const PushStatusOptions: any[] = [
|
|||
label: "Error",
|
||||
value: "PUSH_ERROR"
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
export const NotificationTypeOptions: any[] = [
|
||||
{
|
||||
label: "Discord",
|
||||
value: "DISCORD",
|
||||
},
|
||||
];
|
||||
|
||||
export interface SelectOption {
|
||||
label: string;
|
||||
description: string;
|
||||
value: any;
|
||||
}
|
||||
|
||||
export const EventOptions: SelectOption[] = [
|
||||
{
|
||||
label: "Push Rejected",
|
||||
value: "PUSH_REJECTED",
|
||||
description: "On push rejected for the arrs or download client",
|
||||
},
|
||||
{
|
||||
label: "Push Approved",
|
||||
value: "PUSH_APPROVED",
|
||||
description: "On push approved for the arrs or download client",
|
||||
},
|
||||
{
|
||||
label: "Push Error",
|
||||
value: "PUSH_ERROR",
|
||||
description: "On push error for the arrs or download client",
|
||||
},
|
||||
];
|
||||
|
|
435
web/src/forms/settings/NotifiactionForms.tsx
Normal file
435
web/src/forms/settings/NotifiactionForms.tsx
Normal file
|
@ -0,0 +1,435 @@
|
|||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { Fragment } from "react";
|
||||
import {Field, Form, Formik} from "formik";
|
||||
import type {FieldProps} from "formik";
|
||||
import {XIcon} from "@heroicons/react/solid";
|
||||
import Select, {components} from "react-select";
|
||||
import {
|
||||
SwitchGroupWide,
|
||||
TextFieldWide
|
||||
} from "../../components/inputs";
|
||||
import DEBUG from "../../components/debug";
|
||||
import {EventOptions, NotificationTypeOptions} from "../../domain/constants";
|
||||
import {useMutation} from "react-query";
|
||||
import {APIClient} from "../../api/APIClient";
|
||||
import {queryClient} from "../../App";
|
||||
import {toast} from "react-hot-toast";
|
||||
import Toast from "../../components/notifications/Toast";
|
||||
import {SlideOver} from "../../components/panels";
|
||||
|
||||
|
||||
const Input = (props: any) => {
|
||||
return (
|
||||
<components.Input
|
||||
{...props}
|
||||
inputClassName="outline-none border-none shadow-none focus:ring-transparent"
|
||||
className="text-gray-400 dark:text-gray-100"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const Control = (props: any) => {
|
||||
return (
|
||||
<components.Control
|
||||
{...props}
|
||||
className="p-1 block w-full dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:text-gray-100 sm:text-sm"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const Menu = (props: any) => {
|
||||
return (
|
||||
<components.Menu
|
||||
{...props}
|
||||
className="dark:bg-gray-800 border border-gray-300 dark:border-gray-700 dark:text-gray-400 rounded-md shadow-sm"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const Option = (props: any) => {
|
||||
return (
|
||||
<components.Option
|
||||
{...props}
|
||||
className="dark:text-gray-400 dark:bg-gray-800 dark:hover:bg-gray-900 dark:focus:bg-gray-900"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function FormFieldsDiscord() {
|
||||
return (
|
||||
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
||||
{/*<div className="px-6 space-y-1">*/}
|
||||
{/* <Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Credentials</Dialog.Title>*/}
|
||||
{/* <p className="text-sm text-gray-500 dark:text-gray-400">*/}
|
||||
{/* Api keys etc*/}
|
||||
{/* </p>*/}
|
||||
{/*</div>*/}
|
||||
|
||||
<TextFieldWide
|
||||
name="webhook"
|
||||
label="Webhook URL"
|
||||
help="Discord channel webhook url"
|
||||
placeholder="https://discordapp.com/api/webhooks/xx/xx"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const componentMap: any = {
|
||||
DISCORD: <FormFieldsDiscord/>,
|
||||
};
|
||||
|
||||
interface NotificationAddFormValues {
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
interface AddProps {
|
||||
isOpen: boolean;
|
||||
toggle: any;
|
||||
}
|
||||
|
||||
export function NotificationAddForm({isOpen, toggle}: AddProps) {
|
||||
const mutation = useMutation(
|
||||
(notification: Notification) => APIClient.notifications.create(notification),
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(['notifications']);
|
||||
toast.custom((t) => <Toast type="success" body="Notification added!" t={t} />)
|
||||
toggle()
|
||||
},
|
||||
onError: () => {
|
||||
toast.custom((t) => <Toast type="error" body="Notification could not be added" t={t} />)
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const onSubmit = (formData: any) => {
|
||||
mutation.mutate(formData)
|
||||
}
|
||||
|
||||
const validate = (values: NotificationAddFormValues) => {
|
||||
const errors = {} as any;
|
||||
if (!values.name)
|
||||
errors.name = "Required";
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
return (
|
||||
<Transition.Root show={isOpen} as={Fragment}>
|
||||
<Dialog as="div" static className="fixed inset-0 overflow-hidden" open={isOpen} onClose={toggle}>
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<Dialog.Overlay className="absolute inset-0"/>
|
||||
|
||||
<div className="fixed inset-y-0 right-0 pl-10 max-w-full flex sm:pl-16">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="transform transition ease-in-out duration-500 sm:duration-700"
|
||||
enterFrom="translate-x-full"
|
||||
enterTo="translate-x-0"
|
||||
leave="transform transition ease-in-out duration-500 sm:duration-700"
|
||||
leaveFrom="translate-x-0"
|
||||
leaveTo="translate-x-full"
|
||||
>
|
||||
<div className="w-screen max-w-2xl dark:border-gray-700 border-l">
|
||||
<Formik
|
||||
enableReinitialize={true}
|
||||
initialValues={{
|
||||
enabled: true,
|
||||
type: "",
|
||||
name: "",
|
||||
webhook: "",
|
||||
events: [],
|
||||
}}
|
||||
onSubmit={onSubmit}
|
||||
validate={validate}
|
||||
>
|
||||
{({values}) => (
|
||||
<Form className="h-full flex flex-col bg-white dark:bg-gray-800 shadow-xl overflow-y-scroll">
|
||||
<div className="flex-1">
|
||||
<div className="px-4 py-6 bg-gray-50 dark:bg-gray-900 sm:px-6">
|
||||
<div className="flex items-start justify-between space-x-3">
|
||||
<div className="space-y-1">
|
||||
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Add
|
||||
Notifications</Dialog.Title>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-200">
|
||||
Trigger notifications on different events.
|
||||
</p>
|
||||
</div>
|
||||
<div className="h-7 flex items-center">
|
||||
<button
|
||||
type="button"
|
||||
className="bg-white dark:bg-gray-700 rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
||||
onClick={toggle}
|
||||
>
|
||||
<span className="sr-only">Close panel</span>
|
||||
<XIcon className="h-6 w-6" aria-hidden="true"/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TextFieldWide name="name" label="Name" required={true}/>
|
||||
|
||||
<div className="space-y-4 divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<div className="py-4 flex items-center justify-between space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="type"
|
||||
className="block text-sm font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Type
|
||||
</label>
|
||||
</div>
|
||||
<div className="sm:col-span-2">
|
||||
<Field name="type" type="select">
|
||||
{({
|
||||
field,
|
||||
form: {setFieldValue, resetForm}
|
||||
}: FieldProps) => (
|
||||
<Select {...field}
|
||||
isClearable={true}
|
||||
isSearchable={true}
|
||||
components={{Input, Control, Menu, Option}}
|
||||
placeholder="Choose a type"
|
||||
styles={{
|
||||
singleValue: (base) => ({
|
||||
...base,
|
||||
color: "unset"
|
||||
})
|
||||
}}
|
||||
theme={(theme) => ({
|
||||
...theme,
|
||||
spacing: {
|
||||
...theme.spacing,
|
||||
controlHeight: 30,
|
||||
baseUnit: 2,
|
||||
}
|
||||
})}
|
||||
value={field?.value && field.value.value}
|
||||
onChange={(option: any) => {
|
||||
resetForm()
|
||||
// setFieldValue("name", option?.label ?? "")
|
||||
setFieldValue(field.name, option?.value ?? "")
|
||||
}}
|
||||
options={NotificationTypeOptions}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
||||
<SwitchGroupWide name="enabled" label="Enabled"/>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
||||
<div className="px-6 space-y-1">
|
||||
<Dialog.Title
|
||||
className="text-lg font-medium text-gray-900 dark:text-white">Events</Dialog.Title>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Select what events to trigger on
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1 px-4 sm:space-y-0 sm:grid sm:gap-4 sm:px-6 sm:py-5">
|
||||
<EventCheckBoxes />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{componentMap[values.type]}
|
||||
</div>
|
||||
|
||||
<div className="flex-shrink-0 px-4 border-t border-gray-200 dark:border-gray-700 py-5 sm:px-6">
|
||||
<div className="space-x-3 flex justify-end">
|
||||
<button
|
||||
type="button"
|
||||
className="bg-white dark:bg-gray-700 py-2 px-4 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-blue-500"
|
||||
onClick={toggle}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-blue-500"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DEBUG values={values}/>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition.Root>
|
||||
)
|
||||
}
|
||||
|
||||
const EventCheckBoxes = () => (
|
||||
<fieldset className="space-y-5">
|
||||
<legend className="sr-only">Notifications</legend>
|
||||
{EventOptions.map((e, idx) => (
|
||||
<div key={idx} className="relative flex items-start">
|
||||
<div className="flex items-center h-5">
|
||||
<Field
|
||||
id={`events-${e.value}`}
|
||||
aria-describedby={`events-${e.value}-description`}
|
||||
name="events"
|
||||
type="checkbox"
|
||||
value={e.value}
|
||||
className="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded"
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-3 text-sm">
|
||||
<label htmlFor={`events-${e.value}`}
|
||||
className="font-medium text-gray-900 dark:text-gray-100">
|
||||
{e.label}
|
||||
</label>
|
||||
{e.description && (
|
||||
<p className="text-gray-500">{e.description}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</fieldset>
|
||||
)
|
||||
|
||||
interface UpdateProps {
|
||||
isOpen: boolean;
|
||||
toggle: any;
|
||||
notification: Notification;
|
||||
}
|
||||
|
||||
export function NotificationUpdateForm({isOpen, toggle, notification}: UpdateProps) {
|
||||
const mutation = useMutation(
|
||||
(notification: Notification) => APIClient.notifications.update(notification),
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(["notifications"]);
|
||||
toast.custom((t) => <Toast type="success" body={`${notification.name} was updated successfully`} t={t}/>)
|
||||
toggle();
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const deleteMutation = useMutation(
|
||||
(notificationID: number) => APIClient.notifications.delete(notificationID),
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(["notifications"]);
|
||||
toast.custom((t) => <Toast type="success" body={`${notification.name} was deleted.`} t={t}/>)
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const onSubmit = (formData: any) => {
|
||||
mutation.mutate(formData);
|
||||
}
|
||||
|
||||
const deleteAction = () => {
|
||||
deleteMutation.mutate(notification.id);
|
||||
};
|
||||
|
||||
const initialValues = {
|
||||
id: notification.id,
|
||||
enabled: notification.enabled,
|
||||
type: notification.type,
|
||||
name: notification.name,
|
||||
webhook: notification.webhook,
|
||||
events: notification.events || [],
|
||||
}
|
||||
|
||||
return (
|
||||
<SlideOver
|
||||
type="UPDATE"
|
||||
title="Notification"
|
||||
isOpen={isOpen}
|
||||
toggle={toggle}
|
||||
onSubmit={onSubmit}
|
||||
deleteAction={deleteAction}
|
||||
initialValues={initialValues}
|
||||
>
|
||||
{(values) => (
|
||||
<div>
|
||||
<TextFieldWide name="name" label="Name" required={true}/>
|
||||
|
||||
<div className="space-y-4 divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<div className="py-4 flex items-center justify-between space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="type"
|
||||
className="block text-sm font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Type
|
||||
</label>
|
||||
</div>
|
||||
<div className="sm:col-span-2">
|
||||
<Field name="type" type="select">
|
||||
{({field, form: {setFieldValue, resetForm}}: FieldProps) => (
|
||||
<Select {...field}
|
||||
isClearable={true}
|
||||
isSearchable={true}
|
||||
components={{Input, Control, Menu, Option}}
|
||||
|
||||
placeholder="Choose a type"
|
||||
styles={{
|
||||
singleValue: (base) => ({
|
||||
...base,
|
||||
color: "unset"
|
||||
})
|
||||
}}
|
||||
theme={(theme) => ({
|
||||
...theme,
|
||||
spacing: {
|
||||
...theme.spacing,
|
||||
controlHeight: 30,
|
||||
baseUnit: 2,
|
||||
}
|
||||
})}
|
||||
value={field?.value && NotificationTypeOptions.find(o => o.value == field?.value)}
|
||||
onChange={(option: any) => {
|
||||
resetForm()
|
||||
setFieldValue(field.name, option?.value ?? "")
|
||||
}}
|
||||
options={NotificationTypeOptions}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
||||
<SwitchGroupWide name="enabled" label="Enabled"/>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
||||
<div className="px-6 space-y-1">
|
||||
<Dialog.Title
|
||||
className="text-lg font-medium text-gray-900 dark:text-white">Events</Dialog.Title>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Select what events to trigger on
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1 px-4 sm:space-y-0 sm:grid sm:gap-4 sm:px-6 sm:py-5">
|
||||
<EventCheckBoxes />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{componentMap[values.type]}
|
||||
</div>
|
||||
)}
|
||||
</SlideOver>
|
||||
)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import {CogIcon, CollectionIcon, DownloadIcon, KeyIcon} from '@heroicons/react/outline'
|
||||
import {BellIcon, CogIcon, CollectionIcon, DownloadIcon, KeyIcon} from '@heroicons/react/outline'
|
||||
import {NavLink, Route, Switch as RouteSwitch, useLocation, useRouteMatch} from "react-router-dom";
|
||||
|
||||
import { classNames } from "../utils";
|
||||
|
@ -8,17 +8,18 @@ import ApplicationSettings from "./settings/Application";
|
|||
import DownloadClientSettings from "./settings/DownloadClient";
|
||||
import { RegexPlayground } from './settings/RegexPlayground';
|
||||
import ReleaseSettings from "./settings/Releases";
|
||||
import NotificationSettings from "./settings/Notifications";
|
||||
|
||||
const subNavigation = [
|
||||
{name: 'Application', href: '', icon: CogIcon, current: true},
|
||||
{name: 'Indexers', href: 'indexers', icon: KeyIcon, current: false},
|
||||
{name: 'IRC', href: 'irc', icon: KeyIcon, current: false},
|
||||
{name: 'Clients', href: 'clients', icon: DownloadIcon, current: false},
|
||||
{name: 'Notifications', href: 'notifications', icon: BellIcon, current: false},
|
||||
{name: 'Releases', href: 'releases', icon: CollectionIcon, current: false},
|
||||
// {name: 'Regex Playground', href: 'regex-playground', icon: CogIcon, current: false}
|
||||
// {name: 'Actions', href: 'actions', icon: PlayIcon, current: false},
|
||||
// {name: 'Rules', href: 'rules', icon: ClipboardCheckIcon, current: false},
|
||||
// {name: 'Notifications', href: 'notifications', icon: BellIcon, current: false},
|
||||
]
|
||||
|
||||
function SubNavLink({item, url}: any) {
|
||||
|
@ -93,6 +94,10 @@ export default function Settings() {
|
|||
<DownloadClientSettings/>
|
||||
</Route>
|
||||
|
||||
<Route path={`${url}/notifications`}>
|
||||
<NotificationSettings />
|
||||
</Route>
|
||||
|
||||
<Route path={`${url}/releases`}>
|
||||
<ReleaseSettings/>
|
||||
</Route>
|
||||
|
|
119
web/src/screens/settings/Notifications.tsx
Normal file
119
web/src/screens/settings/Notifications.tsx
Normal file
|
@ -0,0 +1,119 @@
|
|||
import { useQuery } from "react-query";
|
||||
import { APIClient } from "../../api/APIClient";
|
||||
import { EmptySimple } from "../../components/emptystates";
|
||||
import { useToggle } from "../../hooks/hooks";
|
||||
import { NotificationAddForm, NotificationUpdateForm } from "../../forms/settings/NotifiactionForms";
|
||||
import { Switch } from "@headlessui/react";
|
||||
import { classNames } from "../../utils";
|
||||
|
||||
function NotificationSettings() {
|
||||
const [addNotificationsIsOpen, toggleAddNotifications] = useToggle(false)
|
||||
|
||||
const { data } = useQuery<Notification[], Error>('notifications', APIClient.notifications.getAll,
|
||||
{
|
||||
refetchOnWindowFocus: false
|
||||
}
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="divide-y divide-gray-200 lg:col-span-9">
|
||||
<NotificationAddForm isOpen={addNotificationsIsOpen} toggle={toggleAddNotifications} />
|
||||
|
||||
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
||||
<div className="-ml-4 -mt-4 flex justify-between items-center flex-wrap sm:flex-nowrap">
|
||||
<div className="ml-4 mt-4">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">Notifications</h3>
|
||||
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
Send notifications on events
|
||||
</p>
|
||||
</div>
|
||||
<div className="ml-4 mt-4 flex-shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
onClick={toggleAddNotifications}
|
||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 dark:bg-blue-600 hover:bg-indigo-700 dark:hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||
>
|
||||
Add new
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{data && data.length > 0 ?
|
||||
<section className="mt-6 light:bg-white dark:bg-gray-800 light:shadow sm:rounded-md">
|
||||
<ol className="min-w-full">
|
||||
<li className="grid grid-cols-12 gap-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<div className="col-span-1 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Enabled</div>
|
||||
<div className="col-span-2 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Name</div>
|
||||
<div className="col-span-2 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Type</div>
|
||||
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Events</div>
|
||||
</li>
|
||||
|
||||
{data && data.map((n: Notification) => (
|
||||
<ListItem key={n.id} notification={n} />
|
||||
))}
|
||||
</ol>
|
||||
</section>
|
||||
: <EmptySimple title="No notifications setup" subtitle="Add a new notification" buttonText="New notification" buttonAction={toggleAddNotifications} />}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface ListItemProps {
|
||||
notification: Notification;
|
||||
}
|
||||
|
||||
function ListItem({ notification }: ListItemProps) {
|
||||
const [updateFormIsOpen, toggleUpdateForm] = useToggle(false)
|
||||
|
||||
return (
|
||||
<li key={notification.id} className="text-gray-500 dark:text-gray-400">
|
||||
<NotificationUpdateForm isOpen={updateFormIsOpen} toggle={toggleUpdateForm} notification={notification} />
|
||||
|
||||
<div className="grid grid-cols-12 gap-4 items-center py-4">
|
||||
<div className="col-span-1 flex items-center sm:px-6 ">
|
||||
<Switch
|
||||
checked={notification.enabled}
|
||||
onChange={toggleUpdateForm}
|
||||
className={classNames(
|
||||
notification.enabled ? 'bg-teal-500 dark:bg-blue-500' : 'bg-gray-200 dark:bg-gray-600',
|
||||
'relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500'
|
||||
)}
|
||||
>
|
||||
<span className="sr-only">Use setting</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className={classNames(
|
||||
notification.enabled ? 'translate-x-5' : 'translate-x-0',
|
||||
'inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200'
|
||||
)}
|
||||
/>
|
||||
</Switch>
|
||||
</div>
|
||||
<div className="col-span-2 flex items-center sm:px-6 ">
|
||||
{notification.name}
|
||||
</div>
|
||||
<div className="col-span-2 flex items-center sm:px-6 ">
|
||||
{notification.type}
|
||||
</div>
|
||||
<div className="col-span-5 flex items-center sm:px-6 ">
|
||||
{notification.events.map((n, idx) => (
|
||||
<span
|
||||
key={idx}
|
||||
className="mr-2 inline-flex items-center px-2.5 py-0.5 rounded-md text-sm font-medium bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-400"
|
||||
>
|
||||
{n}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="col-span-1 flex items-center sm:px-6 ">
|
||||
<span className="text-indigo-600 dark:text-gray-300 hover:text-indigo-900 cursor-pointer" onClick={toggleUpdateForm}>
|
||||
Edit
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
export default NotificationSettings;
|
10
web/src/types/Notification.d.ts
vendored
Normal file
10
web/src/types/Notification.d.ts
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
type NotificationType = 'DISCORD';
|
||||
|
||||
interface Notification {
|
||||
id: number;
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
type: NotificationType;
|
||||
events: string[];
|
||||
webhook: string;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue