diff --git a/go.mod b/go.mod index 2aa6546f..87b0f177 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ require ( github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557 github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560 - github.com/Rhymen/go-whatsapp v0.1.2-0.20201226125722-8029c28f5c5a + github.com/Rhymen/go-whatsapp v0.1.2-0.20210126174449-3c094ebae0ce github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20200922220614-e4a51dfb52e4 // indirect github.com/SevereCloud/vksdk/v2 v2.9.0 github.com/d5/tengo/v2 v2.6.2 @@ -22,7 +22,7 @@ require ( github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7 github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20201206215757-c1d86d75b9f8 - github.com/matterbridge/discordgo v0.22.1 + github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7 github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050 github.com/matterbridge/gozulipbot v0.0.0-20200820220548-be5824faa913 @@ -41,19 +41,19 @@ require ( github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca github.com/shazow/ssh-chat v1.10.1 github.com/sirupsen/logrus v1.7.0 - github.com/slack-go/slack v0.7.4 + github.com/slack-go/slack v0.8.0 github.com/spf13/afero v1.3.4 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/viper v1.7.1 - github.com/stretchr/testify v1.6.1 + github.com/stretchr/testify v1.7.0 github.com/vincent-petithory/dataurl v0.0.0-20191104211930-d1553a71de50 github.com/writeas/go-strip-markdown v2.0.1+incompatible github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect github.com/yaegashi/msgraph.go v0.1.4 github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2 golang.org/x/image v0.0.0-20201208152932-35266b937fa6 - golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5 + golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c gomod.garykim.dev/nc-talk v0.1.7 gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376 layeh.com/gumble v0.0.0-20200818122324-146f9205029b diff --git a/go.sum b/go.sum index b729ac27..56e15030 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,8 @@ github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBK github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA= github.com/Rhymen/go-whatsapp v0.1.2-0.20201226125722-8029c28f5c5a h1:xE1ogaIgFJQbEDoIkiAkMH9wVEAmlKOy/M+kf1xmtCY= github.com/Rhymen/go-whatsapp v0.1.2-0.20201226125722-8029c28f5c5a/go.mod h1:o7jjkvKnigfu432dMbQ/w4PH0Yp5u4Y6ysCNjUlcYCk= +github.com/Rhymen/go-whatsapp v0.1.2-0.20210126174449-3c094ebae0ce h1:qitALaMtz6i05smexphqLty1gGc7Viwhn8bdSRmp4UM= +github.com/Rhymen/go-whatsapp v0.1.2-0.20210126174449-3c094ebae0ce/go.mod h1:o7jjkvKnigfu432dMbQ/w4PH0Yp5u4Y6ysCNjUlcYCk= github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:zgCiQtBtZ4P4gFWvwl9aashsdwOcbb/EHOGRmSzM8ME= github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU= github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw= @@ -550,6 +552,8 @@ github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd h1:xVrqJK3xHRE github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20201206215757-c1d86d75b9f8 h1:2iHni9FGPRRnaZrknLp+Kyr1CWbRIRUjp89TNpkqy3I= github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20201206215757-c1d86d75b9f8/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A= +github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7 h1:4J2YZuY8dIYrxbLMsWGqPZb/B59ygCwSBkyZHez5PSY= +github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7/go.mod h1:411nZYv0UMMrtppR5glXop1foboJiFAowy+42U+Ahvw= github.com/matterbridge/discordgo v0.22.1 h1:Wh2NXfvF4egJDxX7jEvtgxJgT/ZOqD/5tfcIsNnHJ9o= github.com/matterbridge/discordgo v0.22.1/go.mod h1:411nZYv0UMMrtppR5glXop1foboJiFAowy+42U+Ahvw= github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible h1:oaOqwbg5HxHRxvAbd84ks0Okwoc1ISyUZ87EiVJFhGI= @@ -846,6 +850,8 @@ github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTe github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo= github.com/slack-go/slack v0.7.4 h1:Z+7CmUDV+ym4lYLA4NNLFIpr3+nDgViHrx8xsuXgrYs= github.com/slack-go/slack v0.7.4/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM= +github.com/slack-go/slack v0.8.0 h1:ANyLY5KHLV+MxLJDQum2IuHTLwbCbDtaWY405X1EU9U= +github.com/slack-go/slack v0.8.0/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= @@ -901,6 +907,8 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= @@ -1147,6 +1155,8 @@ golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BG golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5 h1:Lm4OryKCca1vehdsWogr9N4t7NfZxLbJoc/H0w4K4S4= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c h1:HiAZXo96zOhVhtFHchj/ojzoxCFiPrp9/j0GtS38V3g= +golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/vendor/github.com/Rhymen/go-whatsapp/contact.go b/vendor/github.com/Rhymen/go-whatsapp/contact.go index 92d0a4ad..e17f724f 100644 --- a/vendor/github.com/Rhymen/go-whatsapp/contact.go +++ b/vendor/github.com/Rhymen/go-whatsapp/contact.go @@ -2,9 +2,11 @@ package whatsapp import ( "fmt" - "github.com/Rhymen/go-whatsapp/binary" "strconv" + "strings" "time" + + "github.com/Rhymen/go-whatsapp/binary" ) type Presence string @@ -241,3 +243,46 @@ func buildParticipantNodes(participants []string) []binary.Node { } return p } + +func (wac *Conn) BlockContact(jid string) (<-chan string, error) { + return wac.handleBlockContact("add", jid) +} + +func (wac *Conn) UnblockContact(jid string) (<-chan string, error) { + return wac.handleBlockContact("remove", jid) +} + +func (wac *Conn) handleBlockContact(action, jid string) (<-chan string, error) { + ts := time.Now().Unix() + tag := fmt.Sprintf("%d.--%d", ts, wac.msgCount) + + netsplit := strings.Split(jid, "@") + cusjid := netsplit[0] + "@c.us" + + n := binary.Node{ + Description: "action", + Attributes: map[string]string{ + "type": "set", + "epoch": strconv.Itoa(wac.msgCount), + }, + Content: []interface{}{ + binary.Node{ + Description: "block", + Attributes: map[string]string{ + "type": action, + }, + Content: []binary.Node{ + { + Description: "user", + Attributes: map[string]string{ + "jid": cusjid, + }, + Content: nil, + }, + }, + }, + }, + } + + return wac.writeBinary(n, contact, ignore, tag) +} diff --git a/vendor/github.com/Rhymen/go-whatsapp/read.go b/vendor/github.com/Rhymen/go-whatsapp/read.go index 1621c0f5..a69147a6 100644 --- a/vendor/github.com/Rhymen/go-whatsapp/read.go +++ b/vendor/github.com/Rhymen/go-whatsapp/read.go @@ -83,10 +83,8 @@ func (wac *Conn) processReadData(msgType int, msg []byte) error { // chan string to something like chan map[string]interface{}. The unmarshalling // in several places, especially in session.go, would then be gone. listener <- data[1] - - wac.listener.Lock() - delete(wac.listener.m, data[0]) - wac.listener.Unlock() + close(listener) + wac.removeListener(data[0]) } else if msgType == websocket.BinaryMessage { wac.loginSessionLock.RLock() sess := wac.session diff --git a/vendor/github.com/Rhymen/go-whatsapp/write.go b/vendor/github.com/Rhymen/go-whatsapp/write.go index 74f43c42..e427825c 100644 --- a/vendor/github.com/Rhymen/go-whatsapp/write.go +++ b/vendor/github.com/Rhymen/go-whatsapp/write.go @@ -15,15 +15,30 @@ import ( "github.com/pkg/errors" ) +func (wac *Conn) addListener(ch chan string, messageTag string) { + wac.listener.Lock() + wac.listener.m[messageTag] = ch + wac.listener.Unlock() +} + +func (wac *Conn) removeListener(answerMessageTag string) { + wac.listener.Lock() + delete(wac.listener.m, answerMessageTag) + wac.listener.Unlock() +} + //writeJson enqueues a json message into the writeChan func (wac *Conn) writeJson(data []interface{}) (<-chan string, error) { + ch := make(chan string, 1) + wac.writerLock.Lock() defer wac.writerLock.Unlock() d, err := json.Marshal(data) if err != nil { - return nil, err + close(ch) + return ch, err } ts := time.Now().Unix() @@ -35,9 +50,13 @@ func (wac *Conn) writeJson(data []interface{}) (<-chan string, error) { wac.timeTag = tss[len(tss)-3:] } - ch, err := wac.write(websocket.TextMessage, messageTag, bytes) + wac.addListener(ch, messageTag) + + err = wac.write(websocket.TextMessage, bytes) if err != nil { - return nil, err + close(ch) + wac.removeListener(messageTag) + return ch, err } wac.msgCount++ @@ -45,8 +64,12 @@ func (wac *Conn) writeJson(data []interface{}) (<-chan string, error) { } func (wac *Conn) writeBinary(node binary.Node, metric metric, flag flag, messageTag string) (<-chan string, error) { + + ch := make(chan string, 1) + if len(messageTag) < 2 { - return nil, ErrMissingMessageTag + close(ch) + return ch, ErrMissingMessageTag } wac.writerLock.Lock() @@ -54,16 +77,21 @@ func (wac *Conn) writeBinary(node binary.Node, metric metric, flag flag, message data, err := wac.encryptBinaryMessage(node) if err != nil { - return nil, errors.Wrap(err, "encryptBinaryMessage(node) failed") + close(ch) + return ch, errors.Wrap(err, "encryptBinaryMessage(node) failed") } bytes := []byte(messageTag + ",") bytes = append(bytes, byte(metric), byte(flag)) bytes = append(bytes, data...) - ch, err := wac.write(websocket.BinaryMessage, messageTag, bytes) + wac.addListener(ch, messageTag) + + err = wac.write(websocket.BinaryMessage, bytes) if err != nil { - return nil, errors.Wrap(err, "failed to write message") + close(ch) + wac.removeListener(messageTag) + return ch, errors.Wrap(err, "failed to write message") } wac.msgCount++ @@ -71,9 +99,15 @@ func (wac *Conn) writeBinary(node binary.Node, metric metric, flag flag, message } func (wac *Conn) sendKeepAlive() error { + + respChan := make(chan string, 1) + wac.addListener(respChan, "!") + bytes := []byte("?,,") - respChan, err := wac.write(websocket.TextMessage, "!", bytes) + err := wac.write(websocket.TextMessage, bytes) if err != nil { + close(respChan) + wac.removeListener("!") return errors.Wrap(err, "error sending keepAlive") } @@ -122,32 +156,21 @@ func (wac *Conn) sendAdminTest() (bool, error) { } } -func (wac *Conn) write(messageType int, answerMessageTag string, data []byte) (<-chan string, error) { - var ch chan string - if answerMessageTag != "" { - ch = make(chan string, 1) - - wac.listener.Lock() - wac.listener.m[answerMessageTag] = ch - wac.listener.Unlock() - } +func (wac *Conn) write(messageType int, data []byte) error { if wac == nil || wac.ws == nil { - return nil, ErrInvalidWebsocket + return ErrInvalidWebsocket } + wac.ws.Lock() err := wac.ws.conn.WriteMessage(messageType, data) wac.ws.Unlock() if err != nil { - if answerMessageTag != "" { - wac.listener.Lock() - delete(wac.listener.m, answerMessageTag) - wac.listener.Unlock() - } - return nil, errors.Wrap(err, "error writing to websocket") + return errors.Wrap(err, "error writing to websocket") } - return ch, nil + + return nil } func (wac *Conn) encryptBinaryMessage(node binary.Node) (data []byte, err error) { diff --git a/vendor/github.com/matterbridge/discordgo/.travis.yml b/vendor/github.com/matterbridge/discordgo/.travis.yml index c3cb680c..b54331b1 100644 --- a/vendor/github.com/matterbridge/discordgo/.travis.yml +++ b/vendor/github.com/matterbridge/discordgo/.travis.yml @@ -1,7 +1,5 @@ language: go go: - - 1.11.x - - 1.12.x - 1.13.x - 1.14.x - 1.15.x diff --git a/vendor/github.com/matterbridge/discordgo/discord.go b/vendor/github.com/matterbridge/discordgo/discord.go index 0d2aafbb..d319b7b4 100644 --- a/vendor/github.com/matterbridge/discordgo/discord.go +++ b/vendor/github.com/matterbridge/discordgo/discord.go @@ -22,7 +22,7 @@ import ( ) // VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/) -const VERSION = "0.22.0" +const VERSION = "0.23.0" // ErrMFA will be risen by New when the user has 2FA. var ErrMFA = errors.New("account has 2FA enabled") diff --git a/vendor/github.com/matterbridge/discordgo/endpoints.go b/vendor/github.com/matterbridge/discordgo/endpoints.go index 88663fe8..89d56eda 100644 --- a/vendor/github.com/matterbridge/discordgo/endpoints.go +++ b/vendor/github.com/matterbridge/discordgo/endpoints.go @@ -14,7 +14,7 @@ package discordgo import "strconv" // APIVersion is the Discord API version used for the REST and Websocket API. -var APIVersion = "6" +var APIVersion = "8" // Known Discord API Endpoints. var ( @@ -90,7 +90,8 @@ var ( EndpointGuildRoles = func(gID string) string { return EndpointGuilds + gID + "/roles" } EndpointGuildRole = func(gID, rID string) string { return EndpointGuilds + gID + "/roles/" + rID } EndpointGuildInvites = func(gID string) string { return EndpointGuilds + gID + "/invites" } - EndpointGuildEmbed = func(gID string) string { return EndpointGuilds + gID + "/embed" } + EndpointGuildWidget = func(gID string) string { return EndpointGuilds + gID + "/widget" } + EndpointGuildEmbed = EndpointGuildWidget EndpointGuildPrune = func(gID string) string { return EndpointGuilds + gID + "/prune" } EndpointGuildIcon = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" } EndpointGuildIconAnimated = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".gif" } diff --git a/vendor/github.com/matterbridge/discordgo/events.go b/vendor/github.com/matterbridge/discordgo/events.go index dd0e3d84..7488dcc7 100644 --- a/vendor/github.com/matterbridge/discordgo/events.go +++ b/vendor/github.com/matterbridge/discordgo/events.go @@ -196,8 +196,7 @@ type PresencesReplace []*Presence // PresenceUpdate is the data for a PresenceUpdate event. type PresenceUpdate struct { Presence - GuildID string `json:"guild_id"` - Roles []string `json:"roles"` + GuildID string `json:"guild_id"` } // Resumed is the data for a Resumed event. diff --git a/vendor/github.com/matterbridge/discordgo/interactions.go b/vendor/github.com/matterbridge/discordgo/interactions.go new file mode 100644 index 00000000..6fc2f55e --- /dev/null +++ b/vendor/github.com/matterbridge/discordgo/interactions.go @@ -0,0 +1,54 @@ +package discordgo + +import ( + "bytes" + "crypto/ed25519" + "encoding/hex" + "io" + "io/ioutil" + "net/http" +) + +// VerifyInteraction implements message verification of the discord interactions api +// signing algorithm, as documented here: +// https://discord.com/developers/docs/interactions/slash-commands#security-and-authorization +func VerifyInteraction(r *http.Request, key ed25519.PublicKey) bool { + var msg bytes.Buffer + + signature := r.Header.Get("X-Signature-Ed25519") + if signature == "" { + return false + } + + sig, err := hex.DecodeString(signature) + if err != nil { + return false + } + + if len(sig) != ed25519.SignatureSize { + return false + } + + timestamp := r.Header.Get("X-Signature-Timestamp") + if timestamp == "" { + return false + } + + msg.WriteString(timestamp) + + defer r.Body.Close() + var body bytes.Buffer + + // at the end of the function, copy the original body back into the request + defer func() { + r.Body = ioutil.NopCloser(&body) + }() + + // copy body into buffers + _, err = io.Copy(&msg, io.TeeReader(r.Body, &body)) + if err != nil { + return false + } + + return ed25519.Verify(key, msg.Bytes(), sig) +} diff --git a/vendor/github.com/matterbridge/discordgo/message.go b/vendor/github.com/matterbridge/discordgo/message.go index 48589388..61cd0d9c 100644 --- a/vendor/github.com/matterbridge/discordgo/message.go +++ b/vendor/github.com/matterbridge/discordgo/message.go @@ -34,8 +34,10 @@ const ( MessageTypeUserPremiumGuildSubscriptionTierTwo MessageTypeUserPremiumGuildSubscriptionTierThree MessageTypeChannelFollowAdd - MessageTypeGuildDiscoveryDisqualified + MessageTypeGuildDiscoveryDisqualified = iota + 1 MessageTypeGuildDiscoveryRequalified + MessageTypeReply = iota + 4 + MessageTypeApplicationCommand ) // A Message stores all data related to a specific Discord message. @@ -369,7 +371,7 @@ type MessageApplication struct { type MessageReference struct { MessageID string `json:"message_id"` ChannelID string `json:"channel_id"` - GuildID string `json:"guild_id"` + GuildID string `json:"guild_id,omitempty"` } // Reference returns MessageReference of given message diff --git a/vendor/github.com/matterbridge/discordgo/ratelimit.go b/vendor/github.com/matterbridge/discordgo/ratelimit.go index dc48c924..cd96eadf 100644 --- a/vendor/github.com/matterbridge/discordgo/ratelimit.go +++ b/vendor/github.com/matterbridge/discordgo/ratelimit.go @@ -1,6 +1,7 @@ package discordgo import ( + "math" "net/http" "strconv" "strings" @@ -140,20 +141,21 @@ func (b *Bucket) Release(headers http.Header) error { remaining := headers.Get("X-RateLimit-Remaining") reset := headers.Get("X-RateLimit-Reset") global := headers.Get("X-RateLimit-Global") - retryAfter := headers.Get("Retry-After") + resetAfter := headers.Get("X-RateLimit-Reset-After") // Update global and per bucket reset time if the proper headers are available // If global is set, then it will block all buckets until after Retry-After // If Retry-After without global is provided it will use that for the new reset // time since it's more accurate than X-RateLimit-Reset. // If Retry-After after is not proided, it will update the reset time from X-RateLimit-Reset - if retryAfter != "" { - parsedAfter, err := strconv.ParseInt(retryAfter, 10, 64) + if resetAfter != "" { + parsedAfter, err := strconv.ParseFloat(resetAfter, 64) if err != nil { return err } - resetAt := time.Now().Add(time.Duration(parsedAfter) * time.Millisecond) + whole, frac := math.Modf(parsedAfter) + resetAt := time.Now().Add(time.Duration(whole) * time.Second).Add(time.Duration(frac*1000) * time.Millisecond) // Lock either this single bucket or all buckets if global != "" { @@ -168,7 +170,7 @@ func (b *Bucket) Release(headers http.Header) error { return err } - unix, err := strconv.ParseInt(reset, 10, 64) + unix, err := strconv.ParseFloat(reset, 64) if err != nil { return err } @@ -177,7 +179,8 @@ func (b *Bucket) Release(headers http.Header) error { // some extra time is added because without it i still encountered 429's. // The added amount is the lowest amount that gave no 429's // in 1k requests - delta := time.Unix(unix, 0).Sub(discordTime) + time.Millisecond*250 + whole, frac := math.Modf(unix) + delta := time.Unix(int64(whole), 0).Add(time.Duration(frac*1000)*time.Millisecond).Sub(discordTime) + time.Millisecond*250 b.reset = time.Now().Add(delta) } diff --git a/vendor/github.com/matterbridge/discordgo/restapi.go b/vendor/github.com/matterbridge/discordgo/restapi.go index 52f5b787..879a554c 100644 --- a/vendor/github.com/matterbridge/discordgo/restapi.go +++ b/vendor/github.com/matterbridge/discordgo/restapi.go @@ -155,7 +155,7 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b return } s.log(LogInformational, "Rate Limiting %s, retry in %d", urlStr, rl.RetryAfter) - s.handleEvent(rateLimitEventType, RateLimit{TooManyRequests: &rl, URL: urlStr}) + s.handleEvent(rateLimitEventType, &RateLimit{TooManyRequests: &rl, URL: urlStr}) time.Sleep(rl.RetryAfter * time.Millisecond) // we can make the above smarter @@ -465,7 +465,7 @@ func (s *Session) UserGuildSettingsEdit(guildID string, settings *UserGuildSetti // // NOTE: This function is now deprecated and will be removed in the future. // Please see the same function inside state.go -func (s *Session) UserChannelPermissions(userID, channelID string) (apermissions int, err error) { +func (s *Session) UserChannelPermissions(userID, channelID string) (apermissions int64, err error) { // Try to just get permissions from state. apermissions, err = s.State.UserChannelPermissions(userID, channelID) if err == nil { @@ -507,7 +507,7 @@ func (s *Session) UserChannelPermissions(userID, channelID string) (apermissions // Calculates the permissions for a member. // https://support.discord.com/hc/en-us/articles/206141927-How-is-the-permission-hierarchy-structured- -func memberPermissions(guild *Guild, channel *Channel, userID string, roles []string) (apermissions int) { +func memberPermissions(guild *Guild, channel *Channel, userID string, roles []string) (apermissions int64) { if userID == guild.OwnerID { apermissions = PermissionAll return @@ -542,13 +542,11 @@ func memberPermissions(guild *Guild, channel *Channel, userID string, roles []st } } - denies := 0 - allows := 0 - + var denies, allows int64 // Member overwrites can override role overrides, so do two passes for _, overwrite := range channel.PermissionOverwrites { for _, roleID := range roles { - if overwrite.Type == "role" && roleID == overwrite.ID { + if overwrite.Type == PermissionOverwriteTypeRole && roleID == overwrite.ID { denies |= overwrite.Deny allows |= overwrite.Allow break @@ -560,7 +558,7 @@ func memberPermissions(guild *Guild, channel *Channel, userID string, roles []st apermissions |= allows for _, overwrite := range channel.PermissionOverwrites { - if overwrite.Type == "member" && overwrite.ID == userID { + if overwrite.Type == PermissionOverwriteTypeMember && overwrite.ID == userID { apermissions &= ^overwrite.Deny apermissions |= overwrite.Allow break @@ -693,6 +691,19 @@ func (s *Session) GuildBanCreate(guildID, userID string, days int) (err error) { return s.GuildBanCreateWithReason(guildID, userID, "", days) } +// GuildBan finds ban by given guild and user id and returns GuildBan structure +func (s *Session) GuildBan(guildID, userID string) (st *GuildBan, err error) { + + body, err := s.RequestWithBucketID("GET", EndpointGuildBan(guildID, userID), nil, EndpointGuildBan(guildID, userID)) + if err != nil { + return + } + + err = unmarshal(body, &st) + + return +} + // GuildBanCreateWithReason bans the given user from the given guild also providing a reaso. // guildID : The ID of a Guild. // userID : The ID of a User @@ -704,7 +715,7 @@ func (s *Session) GuildBanCreateWithReason(guildID, userID, reason string, days queryParams := url.Values{} if days > 0 { - queryParams.Set("delete-message-days", strconv.Itoa(days)) + queryParams.Set("delete_message_days", strconv.Itoa(days)) } if reason != "" { queryParams.Set("reason", reason) @@ -1796,13 +1807,13 @@ func (s *Session) ChannelInviteCreate(channelID string, i Invite) (st *Invite, e // ChannelPermissionSet creates a Permission Override for the given channel. // NOTE: This func name may changed. Using Set instead of Create because // you can both create a new override or update an override with this function. -func (s *Session) ChannelPermissionSet(channelID, targetID, targetType string, allow, deny int) (err error) { +func (s *Session) ChannelPermissionSet(channelID, targetID string, targetType PermissionOverwriteType, allow, deny int) (err error) { data := struct { - ID string `json:"id"` - Type string `json:"type"` - Allow int `json:"allow"` - Deny int `json:"deny"` + ID string `json:"id"` + Type PermissionOverwriteType `json:"type"` + Allow int `json:"allow"` + Deny int `json:"deny"` }{targetID, targetType, allow, deny} _, err = s.RequestWithBucketID("PUT", EndpointChannelPermission(channelID, targetID), data, EndpointChannelPermission(channelID, "")) diff --git a/vendor/github.com/matterbridge/discordgo/state.go b/vendor/github.com/matterbridge/discordgo/state.go index c89f8bb4..2eeabd80 100644 --- a/vendor/github.com/matterbridge/discordgo/state.go +++ b/vendor/github.com/matterbridge/discordgo/state.go @@ -200,14 +200,10 @@ func (s *State) PresenceAdd(guildID string, presence *Presence) error { //guild.Presences[i] = presence //Update status - guild.Presences[i].Game = presence.Game - guild.Presences[i].Roles = presence.Roles + guild.Presences[i].Activities = presence.Activities if presence.Status != "" { guild.Presences[i].Status = presence.Status } - if presence.Nick != "" { - guild.Presences[i].Nick = presence.Nick - } //Update the optionally sent user information //ID Is a mandatory field so you should not need to check if it is empty @@ -966,24 +962,12 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) { // Member not found; this is a user coming online m = &Member{ GuildID: t.GuildID, - Nick: t.Nick, User: t.User, - Roles: t.Roles, } - } else { - - if t.Nick != "" { - m.Nick = t.Nick - } - if t.User.Username != "" { m.User.Username = t.User.Username } - - // PresenceUpdates always contain a list of roles, so there's no need to check for an empty list here - m.Roles = t.Roles - } err = s.MemberAdd(m) @@ -997,7 +981,7 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) { // UserChannelPermissions returns the permission of a user in a channel. // userID : The ID of the user to calculate permissions for. // channelID : The ID of the channel to calculate permission for. -func (s *State) UserChannelPermissions(userID, channelID string) (apermissions int, err error) { +func (s *State) UserChannelPermissions(userID, channelID string) (apermissions int64, err error) { if s == nil { return 0, ErrNilState } @@ -1022,7 +1006,7 @@ func (s *State) UserChannelPermissions(userID, channelID string) (apermissions i // MessagePermissions returns the permissions of the author of the message // in the channel in which it was sent. -func (s *State) MessagePermissions(message *Message) (apermissions int, err error) { +func (s *State) MessagePermissions(message *Message) (apermissions int64, err error) { if s == nil { return 0, ErrNilState } diff --git a/vendor/github.com/matterbridge/discordgo/structs.go b/vendor/github.com/matterbridge/discordgo/structs.go index c1a63788..8cebfdc5 100644 --- a/vendor/github.com/matterbridge/discordgo/structs.go +++ b/vendor/github.com/matterbridge/discordgo/structs.go @@ -14,6 +14,7 @@ package discordgo import ( "encoding/json" "fmt" + "math" "net/http" "strings" "sync" @@ -322,12 +323,22 @@ type ChannelFollow struct { WebhookID string `json:"webhook_id"` } +// PermissionOverwriteType represents the type of resource on which +// a permission overwrite acts. +type PermissionOverwriteType int + +// The possible permission overwrite types. +const ( + PermissionOverwriteTypeRole PermissionOverwriteType = iota + PermissionOverwriteTypeMember +) + // A PermissionOverwrite holds permission overwrite data for a Channel type PermissionOverwrite struct { - ID string `json:"id"` - Type string `json:"type"` - Deny int `json:"deny"` - Allow int `json:"allow"` + ID string `json:"id"` + Type PermissionOverwriteType `json:"type"` + Deny int64 `json:"deny,string"` + Allow int64 `json:"allow,string"` } // Emoji struct holds data related to Emoji's @@ -427,9 +438,6 @@ type Guild struct { // The ID of the AFK voice channel. AfkChannelID string `json:"afk_channel_id"` - // The ID of the embed channel ID, used for embed widgets. - EmbedChannelID string `json:"embed_channel_id"` - // The user ID of the owner of the guild. OwnerID string `json:"owner_id"` @@ -458,9 +466,6 @@ type Guild struct { // The verification level required for the guild. VerificationLevel VerificationLevel `json:"verification_level"` - // Whether the guild has embedding enabled. - EmbedEnabled bool `json:"embed_enabled"` - // Whether the guild is considered large. This is // determined by a member threshold in the identify packet, // and is currently hard-coded at 250 members in the library. @@ -564,7 +569,7 @@ type Guild struct { ApproximatePresenceCount int `json:"approximate_presence_count"` // Permissions of our user - Permissions int `json:"permissions"` + Permissions int64 `json:"permissions,string"` } // MessageNotifications is the notification level for a guild @@ -606,7 +611,7 @@ type UserGuild struct { Name string `json:"name"` Icon string `json:"icon"` Owner bool `json:"owner"` - Permissions int `json:"permissions"` + Permissions int64 `json:"permissions,string"` } // A GuildParams stores all the data needed to update discord guild settings @@ -650,7 +655,7 @@ type Role struct { // The permissions of the role on the guild (doesn't include channel overrides). // This is a combination of bit masks; the presence of a certain permission can // be checked by performing a bitwise AND between this int and the permission. - Permissions int `json:"permissions"` + Permissions int64 `json:"permissions,string"` } // Mention returns a string which mentions the role @@ -688,39 +693,10 @@ type VoiceState struct { // A Presence stores the online, offline, or idle and game status of Guild members. type Presence struct { - User *User `json:"user"` - Status Status `json:"status"` - Game *Game `json:"game"` - Activities []*Game `json:"activities"` - Nick string `json:"nick"` - Roles []string `json:"roles"` - Since *int `json:"since"` -} - -// GameType is the type of "game" (see GameType* consts) in the Game struct -type GameType int - -// Valid GameType values -const ( - GameTypeGame GameType = iota - GameTypeStreaming - GameTypeListening - GameTypeWatching - GameTypeCustom -) - -// A Game struct holds the name of the "playing .." game for a user -type Game struct { - Name string `json:"name"` - Type GameType `json:"type"` - URL string `json:"url,omitempty"` - Details string `json:"details,omitempty"` - State string `json:"state,omitempty"` - TimeStamps TimeStamps `json:"timestamps,omitempty"` - Assets Assets `json:"assets,omitempty"` - ApplicationID string `json:"application_id,omitempty"` - Instance int8 `json:"instance,omitempty"` - // TODO: Party and Secrets (unknown structure) + User *User `json:"user"` + Status Status `json:"status"` + Activities []*Activity `json:"activities"` + Since *int `json:"since"` } // A TimeStamps struct contains start and end times used in the rich presence "playing .." Game @@ -778,6 +754,9 @@ type Member struct { // When the user used their Nitro boost on the server PremiumSince Timestamp `json:"premium_since"` + + // Is true while the member hasn't accepted the membership screen. + Pending bool `json:"pending"` } // Mention creates a member mention @@ -838,6 +817,26 @@ type TooManyRequests struct { RetryAfter time.Duration `json:"retry_after"` } +// UnmarshalJSON helps support translation of a milliseconds-based float +// into a time.Duration on TooManyRequests. +func (t *TooManyRequests) UnmarshalJSON(b []byte) error { + u := struct { + Bucket string `json:"bucket"` + Message string `json:"message"` + RetryAfter float64 `json:"retry_after"` + }{} + err := json.Unmarshal(b, &u) + if err != nil { + return err + } + + t.Bucket = u.Bucket + t.Message = u.Message + whole, frac := math.Modf(u.RetryAfter) + t.RetryAfter = time.Duration(whole)*time.Second + time.Duration(frac*1000)*time.Millisecond + return nil +} + // A ReadState stores data on the read state of channels. type ReadState struct { MentionCount int `json:"mention_count"` @@ -1117,9 +1116,9 @@ type GatewayStatusUpdate struct { // Activity defines the Activity sent with GatewayStatusUpdate // https://discord.com/developers/docs/topics/gateway#activity-object type Activity struct { - Name string - Type ActivityType - URL string + Name string `json:"name"` + Type ActivityType `json:"type"` + URL string `json:"url,omitempty"` } // ActivityType is the type of Activity (see ActivityType* consts) in the Activity struct @@ -1128,7 +1127,7 @@ type ActivityType int // Valid ActivityType values const ( - ActivityTypeGame GameType = iota + ActivityTypeGame ActivityType = iota ActivityTypeStreaming ActivityTypeListening // ActivityTypeWatching // not valid in this use case? @@ -1145,7 +1144,7 @@ type Identify struct { Shard *[2]int `json:"shard,omitempty"` Presence GatewayStatusUpdate `json:"presence,omitempty"` GuildSubscriptions bool `json:"guild_subscriptions"` - Intents *Intent `json:"intents,omitempty"` + Intents Intent `json:"intents"` } // IdentifyProperties contains the "properties" portion of an Identify packet @@ -1253,6 +1252,7 @@ const ( ErrCodeUnknownUser = 10013 ErrCodeUnknownEmoji = 10014 ErrCodeUnknownWebhook = 10015 + ErrCodeUnknownBan = 10026 ErrCodeBotsCannotUseEndpoint = 20001 ErrCodeOnlyBotsCanUseEndpoint = 20002 @@ -1331,7 +1331,9 @@ const ( IntentsNone Intent = 0 ) -// MakeIntent helps convert a gateway intent value for use in the Identify structure. -func MakeIntent(intents Intent) *Intent { - return &intents +// MakeIntent used to help convert a gateway intent value for use in the Identify structure; +// this was useful to help support the use of a pointer type when intents were optional. +// This is now a no-op, and is not necessary to use. +func MakeIntent(intents Intent) Intent { + return intents } diff --git a/vendor/github.com/matterbridge/discordgo/wsapi.go b/vendor/github.com/matterbridge/discordgo/wsapi.go index 1cf1598e..29a4f613 100644 --- a/vendor/github.com/matterbridge/discordgo/wsapi.go +++ b/vendor/github.com/matterbridge/discordgo/wsapi.go @@ -322,10 +322,10 @@ func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{} // UpdateStatusData ia provided to UpdateStatusComplex() type UpdateStatusData struct { - IdleSince *int `json:"since"` - Game *Game `json:"game"` - AFK bool `json:"afk"` - Status string `json:"status"` + IdleSince *int `json:"since"` + Activities []*Activity `json:"activities"` + AFK bool `json:"afk"` + Status string `json:"status"` } type updateStatusOp struct { @@ -333,7 +333,7 @@ type updateStatusOp struct { Data UpdateStatusData `json:"d"` } -func newUpdateStatusData(idle int, gameType GameType, game, url string) *UpdateStatusData { +func newUpdateStatusData(idle int, activityType ActivityType, name, url string) *UpdateStatusData { usd := &UpdateStatusData{ Status: "online", } @@ -342,43 +342,43 @@ func newUpdateStatusData(idle int, gameType GameType, game, url string) *UpdateS usd.IdleSince = &idle } - if game != "" { - usd.Game = &Game{ - Name: game, - Type: gameType, + if name != "" { + usd.Activities = []*Activity{{ + Name: name, + Type: activityType, URL: url, - } + }} } return usd } -// UpdateStatus is used to update the user's status. +// UpdateGameStatus is used to update the user's status. // If idle>0 then set status to idle. -// If game!="" then set game. -// if otherwise, set status to active, and no game. -func (s *Session) UpdateStatus(idle int, game string) (err error) { - return s.UpdateStatusComplex(*newUpdateStatusData(idle, GameTypeGame, game, "")) +// If name!="" then set game. +// if otherwise, set status to active, and no activity. +func (s *Session) UpdateGameStatus(idle int, name string) (err error) { + return s.UpdateStatusComplex(*newUpdateStatusData(idle, ActivityTypeGame, name, "")) } // UpdateStreamingStatus is used to update the user's streaming status. // If idle>0 then set status to idle. -// If game!="" then set game. -// If game!="" and url!="" then set the status type to streaming with the URL set. +// If name!="" then set game. +// If name!="" and url!="" then set the status type to streaming with the URL set. // if otherwise, set status to active, and no game. -func (s *Session) UpdateStreamingStatus(idle int, game string, url string) (err error) { - gameType := GameTypeGame +func (s *Session) UpdateStreamingStatus(idle int, name string, url string) (err error) { + gameType := ActivityTypeGame if url != "" { - gameType = GameTypeStreaming + gameType = ActivityTypeStreaming } - return s.UpdateStatusComplex(*newUpdateStatusData(idle, gameType, game, url)) + return s.UpdateStatusComplex(*newUpdateStatusData(idle, gameType, name, url)) } // UpdateListeningStatus is used to set the user to "Listening to..." -// If game!="" then set to what user is listening to -// Else, set user to active and no game. -func (s *Session) UpdateListeningStatus(game string) (err error) { - return s.UpdateStatusComplex(*newUpdateStatusData(0, GameTypeListening, game, "")) +// If name!="" then set to what user is listening to +// Else, set user to active and no activity. +func (s *Session) UpdateListeningStatus(name string) (err error) { + return s.UpdateStatusComplex(*newUpdateStatusData(0, ActivityTypeListening, name, "")) } // UpdateStatusComplex allows for sending the raw status update data untouched by discordgo. diff --git a/vendor/github.com/slack-go/slack/.gometalinter.json b/vendor/github.com/slack-go/slack/.gometalinter.json deleted file mode 100644 index 5fa629d4..00000000 --- a/vendor/github.com/slack-go/slack/.gometalinter.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "DisableAll": true, - "Enable": [ - "structcheck", - "vet", - "misspell", - "unconvert", - "interfacer", - "goimports" - ], - "Vendor": true, - "Exclude": ["vendor"], - "Deadline": "300s" -} diff --git a/vendor/github.com/slack-go/slack/apps.go b/vendor/github.com/slack-go/slack/apps.go index cb26ad8e..d9749438 100644 --- a/vendor/github.com/slack-go/slack/apps.go +++ b/vendor/github.com/slack-go/slack/apps.go @@ -3,6 +3,7 @@ package slack import ( "context" "encoding/json" + "net/url" ) type listEventAuthorizationsResponse struct { @@ -41,3 +42,20 @@ func (api *Client) ListEventAuthorizationsContext(ctx context.Context, eventCont return resp.Authorizations, nil } + +func (api *Client) UninstallApp(clientID, clientSecret string) error { + values := url.Values{ + "token": {api.token}, + "client_id": {clientID}, + "client_secret": {clientSecret}, + } + + response := SlackResponse{} + + err := api.getMethod(context.Background(), "apps.uninstall", values, &response) + if err != nil { + return err + } + + return response.Err() +} diff --git a/vendor/github.com/slack-go/slack/block.go b/vendor/github.com/slack-go/slack/block.go index dd4b8715..9946a294 100644 --- a/vendor/github.com/slack-go/slack/block.go +++ b/vendor/github.com/slack-go/slack/block.go @@ -48,11 +48,13 @@ type BlockAction struct { SelectedConversation string `json:"selected_conversation"` SelectedConversations []string `json:"selected_conversations"` SelectedDate string `json:"selected_date"` + SelectedTime string `json:"selected_time"` InitialOption OptionBlockObject `json:"initial_option"` InitialUser string `json:"initial_user"` InitialChannel string `json:"initial_channel"` InitialConversation string `json:"initial_conversation"` InitialDate string `json:"initial_date"` + InitialTime string `json:"initial_time"` } // actionType returns the type of the action diff --git a/vendor/github.com/slack-go/slack/block_conv.go b/vendor/github.com/slack-go/slack/block_conv.go index 656a9ab1..f2d744c4 100644 --- a/vendor/github.com/slack-go/slack/block_conv.go +++ b/vendor/github.com/slack-go/slack/block_conv.go @@ -59,6 +59,8 @@ func (b *Blocks) UnmarshalJSON(data []byte) error { block = &DividerBlock{} case "file": block = &FileBlock{} + case "header": + block = &HeaderBlock{} case "image": block = &ImageBlock{} case "input": @@ -105,6 +107,8 @@ func (b *InputBlock) UnmarshalJSON(data []byte) error { switch s.TypeVal { case "datepicker": e = &DatePickerBlockElement{} + case "timepicker": + e = &TimePickerBlockElement{} case "plain_text_input": e = &PlainTextInputBlockElement{} case "static_select", "external_select", "users_select", "conversations_select", "channels_select": @@ -262,6 +266,12 @@ func (a *Accessory) UnmarshalJSON(data []byte) error { return err } a.DatePickerElement = element.(*DatePickerBlockElement) + case "timepicker": + element, err := unmarshalBlockElement(r, &TimePickerBlockElement{}) + if err != nil { + return err + } + a.TimePickerElement = element.(*TimePickerBlockElement) case "plain_text_input": element, err := unmarshalBlockElement(r, &PlainTextInputBlockElement{}) if err != nil { @@ -324,6 +334,9 @@ func toBlockElement(element *Accessory) BlockElement { if element.DatePickerElement != nil { return element.DatePickerElement } + if element.TimePickerElement != nil { + return element.TimePickerElement + } if element.PlainTextInputElement != nil { return element.PlainTextInputElement } diff --git a/vendor/github.com/slack-go/slack/block_element.go b/vendor/github.com/slack-go/slack/block_element.go index 91b6adc4..4157016c 100644 --- a/vendor/github.com/slack-go/slack/block_element.go +++ b/vendor/github.com/slack-go/slack/block_element.go @@ -8,6 +8,7 @@ const ( METButton MessageElementType = "button" METOverflow MessageElementType = "overflow" METDatepicker MessageElementType = "datepicker" + METTimepicker MessageElementType = "timepicker" METPlainTextInput MessageElementType = "plain_text_input" METRadioButtons MessageElementType = "radio_buttons" @@ -44,6 +45,7 @@ type Accessory struct { ButtonElement *ButtonBlockElement OverflowElement *OverflowBlockElement DatePickerElement *DatePickerBlockElement + TimePickerElement *TimePickerBlockElement PlainTextInputElement *PlainTextInputBlockElement RadioButtonsElement *RadioButtonsBlockElement SelectElement *SelectBlockElement @@ -63,6 +65,8 @@ func NewAccessory(element BlockElement) *Accessory { return &Accessory{OverflowElement: element.(*OverflowBlockElement)} case *DatePickerBlockElement: return &Accessory{DatePickerElement: element.(*DatePickerBlockElement)} + case *TimePickerBlockElement: + return &Accessory{TimePickerElement: element.(*TimePickerBlockElement)} case *PlainTextInputBlockElement: return &Accessory{PlainTextInputElement: element.(*PlainTextInputBlockElement)} case *RadioButtonsBlockElement: @@ -127,10 +131,12 @@ func NewImageBlockElement(imageURL, altText string) *ImageBlockElement { } } +// Style is a style of Button element +// https://api.slack.com/reference/block-kit/block-elements#button__fields type Style string const ( - StyleDefault Style = "default" + StyleDefault Style = "" StylePrimary Style = "primary" StyleDanger Style = "danger" ) @@ -155,7 +161,7 @@ func (s ButtonBlockElement) ElementType() MessageElementType { return s.Type } -// WithStyling adds styling to the button object and returns the modified ButtonBlockElement +// WithStyle adds styling to the button object and returns the modified ButtonBlockElement func (s *ButtonBlockElement) WithStyle(style Style) *ButtonBlockElement { s.Style = style return s @@ -350,6 +356,32 @@ func NewDatePickerBlockElement(actionID string) *DatePickerBlockElement { } } +// TimePickerBlockElement defines an element which lets users easily select a +// time from nice UI. Time picker elements can be used inside of +// section and actions blocks. +// +// More Information: https://api.slack.com/reference/messaging/block-elements#timepicker +type TimePickerBlockElement struct { + Type MessageElementType `json:"type"` + ActionID string `json:"action_id,omitempty"` + Placeholder *TextBlockObject `json:"placeholder,omitempty"` + InitialTime string `json:"initial_time,omitempty"` + Confirm *ConfirmationBlockObject `json:"confirm,omitempty"` +} + +// ElementType returns the type of the Element +func (s TimePickerBlockElement) ElementType() MessageElementType { + return s.Type +} + +// NewTimePickerBlockElement returns an instance of a date picker element +func NewTimePickerBlockElement(actionID string) *TimePickerBlockElement { + return &TimePickerBlockElement{ + Type: METTimepicker, + ActionID: actionID, + } +} + // PlainTextInputBlockElement creates a field where a user can enter freeform // data. // Plain-text input elements are currently only available in modals. diff --git a/vendor/github.com/slack-go/slack/block_object.go b/vendor/github.com/slack-go/slack/block_object.go index cc510b21..d17806ca 100644 --- a/vendor/github.com/slack-go/slack/block_object.go +++ b/vendor/github.com/slack-go/slack/block_object.go @@ -171,7 +171,7 @@ func (s ConfirmationBlockObject) validateType() MessageObjectType { return motConfirmation } -// add styling to confirmation object +// WithStyle add styling to confirmation object func (s *ConfirmationBlockObject) WithStyle(style Style) { s.Style = style } diff --git a/vendor/github.com/slack-go/slack/chat.go b/vendor/github.com/slack-go/slack/chat.go index 439f9373..f5b80346 100644 --- a/vendor/github.com/slack-go/slack/chat.go +++ b/vendor/github.com/slack-go/slack/chat.go @@ -191,6 +191,22 @@ func (api *Client) UnfurlMessage(channelID, timestamp string, unfurls map[string return api.SendMessageContext(context.Background(), channelID, MsgOptionUnfurl(timestamp, unfurls), MsgOptionCompose(options...)) } +// UnfurlMessageWithAuthURL sends an unfurl request containing an +// authentication URL. +// For more details see: +// https://api.slack.com/reference/messaging/link-unfurling#authenticated_unfurls +func (api *Client) UnfurlMessageWithAuthURL(channelID, timestamp string, userAuthURL string, options ...MsgOption) (string, string, string, error) { + return api.UnfurlMessageWithAuthURLContext(context.Background(), channelID, timestamp, userAuthURL, options...) +} + +// UnfurlMessageWithAuthURLContext sends an unfurl request containing an +// authentication URL. +// For more details see: +// https://api.slack.com/reference/messaging/link-unfurling#authenticated_unfurls +func (api *Client) UnfurlMessageWithAuthURLContext(ctx context.Context, channelID, timestamp string, userAuthURL string, options ...MsgOption) (string, string, string, error) { + return api.SendMessageContext(ctx, channelID, MsgOptionUnfurlAuthURL(timestamp, userAuthURL), MsgOptionCompose(options...)) +} + // SendMessage more flexible method for configuring messages. func (api *Client) SendMessage(channel string, options ...MsgOption) (string, string, string, error) { return api.SendMessageContext(context.Background(), channel, options...) @@ -413,6 +429,38 @@ func MsgOptionUnfurl(timestamp string, unfurls map[string]Attachment) MsgOption } } +// MsgOptionUnfurlAuthURL unfurls a message using an auth url based on the timestamp. +func MsgOptionUnfurlAuthURL(timestamp string, userAuthURL string) MsgOption { + return func(config *sendConfig) error { + config.endpoint = config.apiurl + string(chatUnfurl) + config.values.Add("ts", timestamp) + config.values.Add("user_auth_url", userAuthURL) + return nil + } +} + +// MsgOptionUnfurlAuthRequired requests that the user installs the +// Slack app for unfurling. +func MsgOptionUnfurlAuthRequired(timestamp string) MsgOption { + return func(config *sendConfig) error { + config.endpoint = config.apiurl + string(chatUnfurl) + config.values.Add("ts", timestamp) + config.values.Add("user_auth_required", "true") + return nil + } +} + +// MsgOptionUnfurlAuthMessage attaches a message inviting the user to +// authenticate. +func MsgOptionUnfurlAuthMessage(timestamp string, msg string) MsgOption { + return func(config *sendConfig) error { + config.endpoint = config.apiurl + string(chatUnfurl) + config.values.Add("ts", timestamp) + config.values.Add("user_auth_message", msg) + return nil + } +} + // MsgOptionResponseURL supplies a url to use as the endpoint. func MsgOptionResponseURL(url string, responseType string) MsgOption { return func(config *sendConfig) error { diff --git a/vendor/github.com/slack-go/slack/backoff.go b/vendor/github.com/slack-go/slack/internal/backoff/backoff.go similarity index 82% rename from vendor/github.com/slack-go/slack/backoff.go rename to vendor/github.com/slack-go/slack/internal/backoff/backoff.go index 2ba697e7..df210f80 100644 --- a/vendor/github.com/slack-go/slack/backoff.go +++ b/vendor/github.com/slack-go/slack/internal/backoff/backoff.go @@ -1,4 +1,4 @@ -package slack +package backoff import ( "math/rand" @@ -11,7 +11,7 @@ import ( // call to Duration() it is multiplied by Factor. It is capped at // Max. It returns to Min on every call to Reset(). Used in // conjunction with the time package. -type backoff struct { +type Backoff struct { attempts int // Initial value to scale out Initial time.Duration @@ -23,7 +23,7 @@ type backoff struct { // Returns the current value of the counter and then multiplies it // Factor -func (b *backoff) Duration() (dur time.Duration) { +func (b *Backoff) Duration() (dur time.Duration) { // Zero-values are nonsensical, so we use // them to apply defaults if b.Max == 0 { @@ -52,6 +52,11 @@ func (b *backoff) Duration() (dur time.Duration) { } //Resets the current value of the counter back to Min -func (b *backoff) Reset() { +func (b *Backoff) Reset() { b.attempts = 0 } + +// Attempts returns the number of attempts that we had done so far +func (b *Backoff) Attempts() int { + return b.attempts +} diff --git a/vendor/github.com/slack-go/slack/internal/misc/misc.go b/vendor/github.com/slack-go/slack/internal/misc/misc.go new file mode 100644 index 00000000..eab8cdd8 --- /dev/null +++ b/vendor/github.com/slack-go/slack/internal/misc/misc.go @@ -0,0 +1,28 @@ +package misc + +import ( + "fmt" + "net/http" +) + +// StatusCodeError represents an http response error. +// type httpStatusCode interface { HTTPStatusCode() int } to handle it. +type StatusCodeError struct { + Code int + Status string +} + +func (t StatusCodeError) Error() string { + return fmt.Sprintf("slack server error: %s", t.Status) +} + +func (t StatusCodeError) HTTPStatusCode() int { + return t.Code +} + +func (t StatusCodeError) Retryable() bool { + if t.Code >= 500 || t.Code == http.StatusTooManyRequests { + return true + } + return false +} diff --git a/vendor/github.com/slack-go/slack/misc.go b/vendor/github.com/slack-go/slack/misc.go index 336f0afb..821bda86 100644 --- a/vendor/github.com/slack-go/slack/misc.go +++ b/vendor/github.com/slack-go/slack/misc.go @@ -18,6 +18,8 @@ import ( "strconv" "strings" "time" + + "github.com/slack-go/slack/internal/misc" ) // SlackResponse handles parsing out errors from the web api. @@ -42,28 +44,6 @@ func (t SlackResponse) Err() error { return errors.New(t.Error) } -// StatusCodeError represents an http response error. -// type httpStatusCode interface { HTTPStatusCode() int } to handle it. -type statusCodeError struct { - Code int - Status string -} - -func (t statusCodeError) Error() string { - return fmt.Sprintf("slack server error: %s", t.Status) -} - -func (t statusCodeError) HTTPStatusCode() int { - return t.Code -} - -func (t statusCodeError) Retryable() bool { - if t.Code >= 500 || t.Code == http.StatusTooManyRequests { - return true - } - return false -} - // RateLimitedError represents the rate limit respond from slack type RateLimitedError struct { RetryAfter time.Duration @@ -312,7 +292,7 @@ func checkStatusCode(resp *http.Response, d Debug) error { // Slack seems to send an HTML body along with 5xx error codes. Don't parse it. if resp.StatusCode != http.StatusOK { logResponse(resp, d) - return statusCodeError{Code: resp.StatusCode, Status: resp.Status} + return misc.StatusCodeError{Code: resp.StatusCode, Status: resp.Status} } return nil diff --git a/vendor/github.com/slack-go/slack/socket_mode.go b/vendor/github.com/slack-go/slack/socket_mode.go new file mode 100644 index 00000000..69e40d99 --- /dev/null +++ b/vendor/github.com/slack-go/slack/socket_mode.go @@ -0,0 +1,34 @@ +package slack + +import ( + "context" +) + +// SocketModeConnection contains various details about the SocketMode connection. +// It is returned by an "apps.connections.open" API call. +type SocketModeConnection struct { + URL string `json:"url,omitempty"` + Data map[string]interface{} `json:"-"` +} + +type openResponseFull struct { + SlackResponse + SocketModeConnection +} + +// StartSocketModeContext calls the "apps.connections.open" endpoint and returns the provided URL and the full Info block with a custom context. +// +// To have a fully managed Socket Mode connection, use `socketmode.New()`, and call `Run()` on it. +func (api *Client) StartSocketModeContext(ctx context.Context) (info *SocketModeConnection, websocketURL string, err error) { + response := &openResponseFull{} + err = postJSON(ctx, api.httpclient, api.endpoint+"apps.connections.open", api.appLevelToken, nil, response, api) + if err != nil { + return nil, "", err + } + + if response.Err() == nil { + api.Debugln("Using URL:", response.SocketModeConnection.URL) + } + + return &response.SocketModeConnection, response.SocketModeConnection.URL, response.Err() +} diff --git a/vendor/github.com/slack-go/slack/users.go b/vendor/github.com/slack-go/slack/users.go index c2ee8713..5d8cb35f 100644 --- a/vendor/github.com/slack-go/slack/users.go +++ b/vendor/github.com/slack-go/slack/users.go @@ -31,6 +31,7 @@ type UserProfile struct { Image48 string `json:"image_48"` Image72 string `json:"image_72"` Image192 string `json:"image_192"` + Image512 string `json:"image_512"` ImageOriginal string `json:"image_original"` Title string `json:"title"` BotID string `json:"bot_id,omitempty"` diff --git a/vendor/github.com/slack-go/slack/websocket_managed_conn.go b/vendor/github.com/slack-go/slack/websocket_managed_conn.go index 8607b3a3..fe6802e4 100644 --- a/vendor/github.com/slack-go/slack/websocket_managed_conn.go +++ b/vendor/github.com/slack-go/slack/websocket_managed_conn.go @@ -9,6 +9,9 @@ import ( "reflect" "time" + "github.com/slack-go/slack/internal/backoff" + "github.com/slack-go/slack/internal/misc" + "github.com/gorilla/websocket" "github.com/slack-go/slack/internal/errorsx" "github.com/slack-go/slack/internal/timex" @@ -92,7 +95,7 @@ func (rtm *RTM) connect(connectionCount int, useRTMStart bool) (*Info, *websocke // used to provide exponential backoff wait time with jitter before trying // to connect to slack again - boff := &backoff{ + boff := &backoff.Backoff{ Max: 5 * time.Minute, } @@ -103,7 +106,7 @@ func (rtm *RTM) connect(connectionCount int, useRTMStart bool) (*Info, *websocke // send connecting event rtm.IncomingEvents <- RTMEvent{"connecting", &ConnectingEvent{ - Attempt: boff.attempts + 1, + Attempt: boff.Attempts() + 1, ConnectionCount: connectionCount, }} @@ -123,7 +126,7 @@ func (rtm *RTM) connect(connectionCount int, useRTMStart bool) (*Info, *websocke } switch actual := err.(type) { - case statusCodeError: + case misc.StatusCodeError: if actual.Code == http.StatusNotFound { rtm.Debugf("invalid auth when connecting with RTM: %s", err) rtm.IncomingEvents <- RTMEvent{"invalid_auth", &InvalidAuthEvent{}} @@ -138,13 +141,13 @@ func (rtm *RTM) connect(connectionCount int, useRTMStart bool) (*Info, *websocke // any other errors are treated as recoverable and we try again after // sending the event along the IncomingEvents channel rtm.IncomingEvents <- RTMEvent{"connection_error", &ConnectionErrorEvent{ - Attempt: boff.attempts, + Attempt: boff.Attempts(), Backoff: backoff, ErrorObj: err, }} // get time we should wait before attempting to connect again - rtm.Debugf("reconnection %d failed: %s reconnecting in %v\n", boff.attempts, err, backoff) + rtm.Debugf("reconnection %d failed: %s reconnecting in %v\n", boff.Attempts(), err, backoff) // wait for one of the following to occur, // backoff duration has elapsed, killChannel is signalled, or diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare.go b/vendor/github.com/stretchr/testify/assert/assertion_compare.go index dc200395..41649d26 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_compare.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare.go @@ -13,12 +13,42 @@ const ( compareGreater ) +var ( + intType = reflect.TypeOf(int(1)) + int8Type = reflect.TypeOf(int8(1)) + int16Type = reflect.TypeOf(int16(1)) + int32Type = reflect.TypeOf(int32(1)) + int64Type = reflect.TypeOf(int64(1)) + + uintType = reflect.TypeOf(uint(1)) + uint8Type = reflect.TypeOf(uint8(1)) + uint16Type = reflect.TypeOf(uint16(1)) + uint32Type = reflect.TypeOf(uint32(1)) + uint64Type = reflect.TypeOf(uint64(1)) + + float32Type = reflect.TypeOf(float32(1)) + float64Type = reflect.TypeOf(float64(1)) + + stringType = reflect.TypeOf("") +) + func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { + obj1Value := reflect.ValueOf(obj1) + obj2Value := reflect.ValueOf(obj2) + + // throughout this switch we try and avoid calling .Convert() if possible, + // as this has a pretty big performance impact switch kind { case reflect.Int: { - intobj1 := obj1.(int) - intobj2 := obj2.(int) + intobj1, ok := obj1.(int) + if !ok { + intobj1 = obj1Value.Convert(intType).Interface().(int) + } + intobj2, ok := obj2.(int) + if !ok { + intobj2 = obj2Value.Convert(intType).Interface().(int) + } if intobj1 > intobj2 { return compareGreater, true } @@ -31,8 +61,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.Int8: { - int8obj1 := obj1.(int8) - int8obj2 := obj2.(int8) + int8obj1, ok := obj1.(int8) + if !ok { + int8obj1 = obj1Value.Convert(int8Type).Interface().(int8) + } + int8obj2, ok := obj2.(int8) + if !ok { + int8obj2 = obj2Value.Convert(int8Type).Interface().(int8) + } if int8obj1 > int8obj2 { return compareGreater, true } @@ -45,8 +81,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.Int16: { - int16obj1 := obj1.(int16) - int16obj2 := obj2.(int16) + int16obj1, ok := obj1.(int16) + if !ok { + int16obj1 = obj1Value.Convert(int16Type).Interface().(int16) + } + int16obj2, ok := obj2.(int16) + if !ok { + int16obj2 = obj2Value.Convert(int16Type).Interface().(int16) + } if int16obj1 > int16obj2 { return compareGreater, true } @@ -59,8 +101,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.Int32: { - int32obj1 := obj1.(int32) - int32obj2 := obj2.(int32) + int32obj1, ok := obj1.(int32) + if !ok { + int32obj1 = obj1Value.Convert(int32Type).Interface().(int32) + } + int32obj2, ok := obj2.(int32) + if !ok { + int32obj2 = obj2Value.Convert(int32Type).Interface().(int32) + } if int32obj1 > int32obj2 { return compareGreater, true } @@ -73,8 +121,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.Int64: { - int64obj1 := obj1.(int64) - int64obj2 := obj2.(int64) + int64obj1, ok := obj1.(int64) + if !ok { + int64obj1 = obj1Value.Convert(int64Type).Interface().(int64) + } + int64obj2, ok := obj2.(int64) + if !ok { + int64obj2 = obj2Value.Convert(int64Type).Interface().(int64) + } if int64obj1 > int64obj2 { return compareGreater, true } @@ -87,8 +141,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.Uint: { - uintobj1 := obj1.(uint) - uintobj2 := obj2.(uint) + uintobj1, ok := obj1.(uint) + if !ok { + uintobj1 = obj1Value.Convert(uintType).Interface().(uint) + } + uintobj2, ok := obj2.(uint) + if !ok { + uintobj2 = obj2Value.Convert(uintType).Interface().(uint) + } if uintobj1 > uintobj2 { return compareGreater, true } @@ -101,8 +161,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.Uint8: { - uint8obj1 := obj1.(uint8) - uint8obj2 := obj2.(uint8) + uint8obj1, ok := obj1.(uint8) + if !ok { + uint8obj1 = obj1Value.Convert(uint8Type).Interface().(uint8) + } + uint8obj2, ok := obj2.(uint8) + if !ok { + uint8obj2 = obj2Value.Convert(uint8Type).Interface().(uint8) + } if uint8obj1 > uint8obj2 { return compareGreater, true } @@ -115,8 +181,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.Uint16: { - uint16obj1 := obj1.(uint16) - uint16obj2 := obj2.(uint16) + uint16obj1, ok := obj1.(uint16) + if !ok { + uint16obj1 = obj1Value.Convert(uint16Type).Interface().(uint16) + } + uint16obj2, ok := obj2.(uint16) + if !ok { + uint16obj2 = obj2Value.Convert(uint16Type).Interface().(uint16) + } if uint16obj1 > uint16obj2 { return compareGreater, true } @@ -129,8 +201,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.Uint32: { - uint32obj1 := obj1.(uint32) - uint32obj2 := obj2.(uint32) + uint32obj1, ok := obj1.(uint32) + if !ok { + uint32obj1 = obj1Value.Convert(uint32Type).Interface().(uint32) + } + uint32obj2, ok := obj2.(uint32) + if !ok { + uint32obj2 = obj2Value.Convert(uint32Type).Interface().(uint32) + } if uint32obj1 > uint32obj2 { return compareGreater, true } @@ -143,8 +221,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.Uint64: { - uint64obj1 := obj1.(uint64) - uint64obj2 := obj2.(uint64) + uint64obj1, ok := obj1.(uint64) + if !ok { + uint64obj1 = obj1Value.Convert(uint64Type).Interface().(uint64) + } + uint64obj2, ok := obj2.(uint64) + if !ok { + uint64obj2 = obj2Value.Convert(uint64Type).Interface().(uint64) + } if uint64obj1 > uint64obj2 { return compareGreater, true } @@ -157,8 +241,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.Float32: { - float32obj1 := obj1.(float32) - float32obj2 := obj2.(float32) + float32obj1, ok := obj1.(float32) + if !ok { + float32obj1 = obj1Value.Convert(float32Type).Interface().(float32) + } + float32obj2, ok := obj2.(float32) + if !ok { + float32obj2 = obj2Value.Convert(float32Type).Interface().(float32) + } if float32obj1 > float32obj2 { return compareGreater, true } @@ -171,8 +261,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.Float64: { - float64obj1 := obj1.(float64) - float64obj2 := obj2.(float64) + float64obj1, ok := obj1.(float64) + if !ok { + float64obj1 = obj1Value.Convert(float64Type).Interface().(float64) + } + float64obj2, ok := obj2.(float64) + if !ok { + float64obj2 = obj2Value.Convert(float64Type).Interface().(float64) + } if float64obj1 > float64obj2 { return compareGreater, true } @@ -185,8 +281,14 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { } case reflect.String: { - stringobj1 := obj1.(string) - stringobj2 := obj2.(string) + stringobj1, ok := obj1.(string) + if !ok { + stringobj1 = obj1Value.Convert(stringType).Interface().(string) + } + stringobj2, ok := obj2.(string) + if !ok { + stringobj2 = obj2Value.Convert(stringType).Interface().(string) + } if stringobj1 > stringobj2 { return compareGreater, true } @@ -240,6 +342,24 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) } +// Positive asserts that the specified element is positive +// +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) +func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + zero := reflect.Zero(reflect.TypeOf(e)) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs) +} + +// Negative asserts that the specified element is negative +// +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) +func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + zero := reflect.Zero(reflect.TypeOf(e)) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs) +} + func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go index 49370eb1..4dfd1229 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_format.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -114,6 +114,24 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) bool { return Error(t, err, append([]interface{}{msg}, args...)...) } +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ErrorIs(t, err, target, append([]interface{}{msg}, args...)...) +} + // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // @@ -321,6 +339,54 @@ func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsil return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...) } +// IsDecreasingf asserts that the collection is decreasing +// +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsDecreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsIncreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasing(t, object, append([]interface{}{msg}, args...)...) +} + // IsTypef asserts that the specified objects are of the same type. func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { @@ -375,6 +441,17 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args . return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...) } +// Negativef asserts that the specified element is negative +// +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") +func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Negative(t, e, append([]interface{}{msg}, args...)...) +} + // Neverf asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // @@ -476,6 +553,15 @@ func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg s return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) } +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotErrorIs(t, err, target, append([]interface{}{msg}, args...)...) +} + // NotNilf asserts that the specified object is not nil. // // assert.NotNilf(t, err, "error message %s", "formatted") @@ -572,6 +658,17 @@ func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg str return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...) } +// Positivef asserts that the specified element is positive +// +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") +func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Positive(t, e, append([]interface{}{msg}, args...)...) +} + // Regexpf asserts that a specified regexp matches a string. // // assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go index 9db88942..25337a6f 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -204,6 +204,42 @@ func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { return Error(a.t, err, msgAndArgs...) } +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorAs(a.t, err, target, msgAndArgs...) +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorAsf(a.t, err, target, msg, args...) +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorIs(a.t, err, target, msgAndArgs...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorIsf(a.t, err, target, msg, args...) +} + // Errorf asserts that a function returned an error (i.e. not `nil`). // // actualObj, err := SomeFunction() @@ -631,6 +667,102 @@ func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilo return InEpsilonf(a.t, expected, actual, epsilon, msg, args...) } +// IsDecreasing asserts that the collection is decreasing +// +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) +func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsDecreasing(a.t, object, msgAndArgs...) +} + +// IsDecreasingf asserts that the collection is decreasing +// +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsDecreasingf(a.t, object, msg, args...) +} + +// IsIncreasing asserts that the collection is increasing +// +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) +func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsIncreasing(a.t, object, msgAndArgs...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsIncreasingf(a.t, object, msg, args...) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) +func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasing(a.t, object, msgAndArgs...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasingf(a.t, object, msg, args...) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) +func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasing(a.t, object, msgAndArgs...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasingf(a.t, object, msg, args...) +} + // IsType asserts that the specified objects are of the same type. func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { @@ -739,6 +871,28 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i return Lessf(a.t, e1, e2, msg, args...) } +// Negative asserts that the specified element is negative +// +// a.Negative(-1) +// a.Negative(-1.23) +func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Negative(a.t, e, msgAndArgs...) +} + +// Negativef asserts that the specified element is negative +// +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") +func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Negativef(a.t, e, msg, args...) +} + // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // @@ -941,6 +1095,24 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str return NotEqualf(a.t, expected, actual, msg, args...) } +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotErrorIs(a.t, err, target, msgAndArgs...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotErrorIsf(a.t, err, target, msg, args...) +} + // NotNil asserts that the specified object is not nil. // // a.NotNil(err) @@ -1133,6 +1305,28 @@ func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) b return Panicsf(a.t, f, msg, args...) } +// Positive asserts that the specified element is positive +// +// a.Positive(1) +// a.Positive(1.23) +func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Positive(a.t, e, msgAndArgs...) +} + +// Positivef asserts that the specified element is positive +// +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") +func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Positivef(a.t, e, msg, args...) +} + // Regexp asserts that a specified regexp matches a string. // // a.Regexp(regexp.MustCompile("start"), "it's starting") diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go new file mode 100644 index 00000000..1c3b4718 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go @@ -0,0 +1,81 @@ +package assert + +import ( + "fmt" + "reflect" +) + +// isOrdered checks that collection contains orderable elements. +func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { + objKind := reflect.TypeOf(object).Kind() + if objKind != reflect.Slice && objKind != reflect.Array { + return false + } + + objValue := reflect.ValueOf(object) + objLen := objValue.Len() + + if objLen <= 1 { + return true + } + + value := objValue.Index(0) + valueInterface := value.Interface() + firstValueKind := value.Kind() + + for i := 1; i < objLen; i++ { + prevValue := value + prevValueInterface := valueInterface + + value = objValue.Index(i) + valueInterface = value.Interface() + + compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind) + + if !isComparable { + return Fail(t, fmt.Sprintf("Can not compare type \"%s\" and \"%s\"", reflect.TypeOf(value), reflect.TypeOf(prevValue)), msgAndArgs...) + } + + if !containsValue(allowedComparesResults, compareResult) { + return Fail(t, fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...) + } + } + + return true +} + +// IsIncreasing asserts that the collection is increasing +// +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) +func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) +func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) +} + +// IsDecreasing asserts that the collection is decreasing +// +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) +func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) +func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go index 914a10d8..bcac4401 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -172,8 +172,8 @@ func isTest(name, prefix string) bool { if len(name) == len(prefix) { // "Test" is ok return true } - rune, _ := utf8.DecodeRuneInString(name[len(prefix):]) - return !unicode.IsLower(rune) + r, _ := utf8.DecodeRuneInString(name[len(prefix):]) + return !unicode.IsLower(r) } func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { @@ -1622,6 +1622,7 @@ var spewConfig = spew.ConfigState{ DisableCapacities: true, SortKeys: true, DisableMethods: true, + MaxDepth: 10, } type tHelper interface { @@ -1693,3 +1694,81 @@ func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.D } } } + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if errors.Is(err, target) { + return true + } + + var expectedText string + if target != nil { + expectedText = target.Error() + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+ + "expected: %q\n"+ + "in chain: %s", expectedText, chain, + ), msgAndArgs...) +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if !errors.Is(err, target) { + return true + } + + var expectedText string + if target != nil { + expectedText = target.Error() + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+ + "found: %q\n"+ + "in chain: %s", expectedText, chain, + ), msgAndArgs...) +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if errors.As(err, target) { + return true + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Should be in error chain:\n"+ + "expected: %q\n"+ + "in chain: %s", target, chain, + ), msgAndArgs...) +} + +func buildErrorChainString(err error) string { + if err == nil { + return "" + } + + e := errors.Unwrap(err) + chain := fmt.Sprintf("%q", err.Error()) + for e != nil { + chain += fmt.Sprintf("\n\t%q", e.Error()) + e = errors.Unwrap(e) + } + return chain +} diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go index ec4624b2..51820df2 100644 --- a/vendor/github.com/stretchr/testify/require/require.go +++ b/vendor/github.com/stretchr/testify/require/require.go @@ -256,6 +256,54 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) { t.FailNow() } +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorAs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorAsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorIs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorIsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + // Errorf asserts that a function returned an error (i.e. not `nil`). // // actualObj, err := SomeFunction() @@ -806,6 +854,126 @@ func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon fl t.FailNow() } +// IsDecreasing asserts that the collection is decreasing +// +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) +func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsDecreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsDecreasingf asserts that the collection is decreasing +// +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsDecreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsIncreasing asserts that the collection is increasing +// +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) +func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsIncreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsIncreasingf asserts that the collection is increasing +// +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsIncreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) +func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonDecreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonDecreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) +func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonIncreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonIncreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + // IsType asserts that the specified objects are of the same type. func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { @@ -944,6 +1112,34 @@ func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...inter t.FailNow() } +// Negative asserts that the specified element is negative +// +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) +func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Negative(t, e, msgAndArgs...) { + return + } + t.FailNow() +} + +// Negativef asserts that the specified element is negative +// +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") +func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Negativef(t, e, msg, args...) { + return + } + t.FailNow() +} + // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // @@ -1200,6 +1396,30 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, t.FailNow() } +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorIs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorIsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + // NotNil asserts that the specified object is not nil. // // assert.NotNil(t, err) @@ -1446,6 +1666,34 @@ func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{} t.FailNow() } +// Positive asserts that the specified element is positive +// +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) +func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Positive(t, e, msgAndArgs...) { + return + } + t.FailNow() +} + +// Positivef asserts that the specified element is positive +// +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") +func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Positivef(t, e, msg, args...) { + return + } + t.FailNow() +} + // Regexp asserts that a specified regexp matches a string. // // assert.Regexp(t, regexp.MustCompile("start"), "it's starting") diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go index 103d7dcb..ed54a9d8 100644 --- a/vendor/github.com/stretchr/testify/require/require_forward.go +++ b/vendor/github.com/stretchr/testify/require/require_forward.go @@ -205,6 +205,42 @@ func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { Error(a.t, err, msgAndArgs...) } +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorAs(a.t, err, target, msgAndArgs...) +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorAsf(a.t, err, target, msg, args...) +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorIs(a.t, err, target, msgAndArgs...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorIsf(a.t, err, target, msg, args...) +} + // Errorf asserts that a function returned an error (i.e. not `nil`). // // actualObj, err := SomeFunction() @@ -632,6 +668,102 @@ func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilo InEpsilonf(a.t, expected, actual, epsilon, msg, args...) } +// IsDecreasing asserts that the collection is decreasing +// +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) +func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsDecreasing(a.t, object, msgAndArgs...) +} + +// IsDecreasingf asserts that the collection is decreasing +// +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsDecreasingf(a.t, object, msg, args...) +} + +// IsIncreasing asserts that the collection is increasing +// +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) +func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsIncreasing(a.t, object, msgAndArgs...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsIncreasingf(a.t, object, msg, args...) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) +func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonDecreasing(a.t, object, msgAndArgs...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonDecreasingf(a.t, object, msg, args...) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) +func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonIncreasing(a.t, object, msgAndArgs...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonIncreasingf(a.t, object, msg, args...) +} + // IsType asserts that the specified objects are of the same type. func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { @@ -740,6 +872,28 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i Lessf(a.t, e1, e2, msg, args...) } +// Negative asserts that the specified element is negative +// +// a.Negative(-1) +// a.Negative(-1.23) +func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Negative(a.t, e, msgAndArgs...) +} + +// Negativef asserts that the specified element is negative +// +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") +func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Negativef(a.t, e, msg, args...) +} + // Never asserts that the given condition doesn't satisfy in waitFor time, // periodically checking the target function each tick. // @@ -942,6 +1096,24 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str NotEqualf(a.t, expected, actual, msg, args...) } +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorIs(a.t, err, target, msgAndArgs...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorIsf(a.t, err, target, msg, args...) +} + // NotNil asserts that the specified object is not nil. // // a.NotNil(err) @@ -1134,6 +1306,28 @@ func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interfa Panicsf(a.t, f, msg, args...) } +// Positive asserts that the specified element is positive +// +// a.Positive(1) +// a.Positive(1.23) +func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Positive(a.t, e, msgAndArgs...) +} + +// Positivef asserts that the specified element is positive +// +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") +func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Positivef(a.t, e, msg, args...) +} + // Regexp asserts that a specified regexp matches a string. // // a.Regexp(regexp.MustCompile("start"), "it's starting") diff --git a/vendor/modules.txt b/vendor/modules.txt index cd9c3550..270c814c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -18,7 +18,7 @@ github.com/Philipp15b/go-steam/protocol/steamlang github.com/Philipp15b/go-steam/rwu github.com/Philipp15b/go-steam/socialcache github.com/Philipp15b/go-steam/steamid -# github.com/Rhymen/go-whatsapp v0.1.2-0.20201226125722-8029c28f5c5a +# github.com/Rhymen/go-whatsapp v0.1.2-0.20210126174449-3c094ebae0ce ## explicit github.com/Rhymen/go-whatsapp github.com/Rhymen/go-whatsapp/binary @@ -140,7 +140,7 @@ github.com/matrix-org/gomatrix github.com/matterbridge/Rocket.Chat.Go.SDK/models github.com/matterbridge/Rocket.Chat.Go.SDK/realtime github.com/matterbridge/Rocket.Chat.Go.SDK/rest -# github.com/matterbridge/discordgo v0.22.1 +# github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7 ## explicit github.com/matterbridge/discordgo # github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible @@ -243,10 +243,12 @@ github.com/sirupsen/logrus github.com/skip2/go-qrcode github.com/skip2/go-qrcode/bitset github.com/skip2/go-qrcode/reedsolomon -# github.com/slack-go/slack v0.7.4 +# github.com/slack-go/slack v0.8.0 ## explicit github.com/slack-go/slack +github.com/slack-go/slack/internal/backoff github.com/slack-go/slack/internal/errorsx +github.com/slack-go/slack/internal/misc github.com/slack-go/slack/internal/timex github.com/slack-go/slack/slackutilsx # github.com/spf13/afero v1.3.4 @@ -264,7 +266,7 @@ github.com/spf13/pflag # github.com/spf13/viper v1.7.1 ## explicit github.com/spf13/viper -# github.com/stretchr/testify v1.6.1 +# github.com/stretchr/testify v1.7.0 ## explicit github.com/stretchr/testify/assert github.com/stretchr/testify/require @@ -352,7 +354,7 @@ golang.org/x/net/http2/h2c golang.org/x/net/http2/hpack golang.org/x/net/idna golang.org/x/net/websocket -# golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5 +# golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c ## explicit golang.org/x/oauth2 golang.org/x/oauth2/clientcredentials