mirror of
https://github.com/nikoksr/notify.git
synced 2025-02-11 13:15:34 +02:00
Merge branch 'main' into dependabot/go_modules/github.com/plivo/plivo-go-5.5.2incompatible
This commit is contained in:
commit
8ac768cb24
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -24,7 +24,7 @@ jobs:
|
|||||||
go-version: 1.15
|
go-version: 1.15
|
||||||
-
|
-
|
||||||
name: Cache Go modules
|
name: Cache Go modules
|
||||||
uses: actions/cache@v2.1.4
|
uses: actions/cache@v2.1.5
|
||||||
with:
|
with:
|
||||||
path: ~/go/pkg/mod
|
path: ~/go/pkg/mod
|
||||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||||
|
2
Makefile
2
Makefile
@ -27,7 +27,7 @@ test:
|
|||||||
|
|
||||||
# gofumports and gci all go files
|
# gofumports and gci all go files
|
||||||
fmt:
|
fmt:
|
||||||
find . -name '*.go' -not -wholename './vendor/*' | while read -r file; do gofumports -w "$$file"; done
|
find . -name '*.go' -not -wholename './vendor/*' | while read -r file; do gofumpt -w "$$file"; done
|
||||||
gci -w -local github.com/nikoksr/notify .
|
gci -w -local github.com/nikoksr/notify .
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@ _ = notifier.Send(
|
|||||||
- *Telegram*
|
- *Telegram*
|
||||||
- *Twitter*
|
- *Twitter*
|
||||||
- *WhatsApp*
|
- *WhatsApp*
|
||||||
|
- *WeChat*
|
||||||
|
|
||||||
## Credits <a id="credits"></a>
|
## Credits <a id="credits"></a>
|
||||||
|
|
||||||
@ -95,6 +96,7 @@ _ = notifier.Send(
|
|||||||
- Slack support: [slack-go/slack](https://github.com/slack-go/slack)
|
- Slack support: [slack-go/slack](https://github.com/slack-go/slack)
|
||||||
- Telegram support: [go-telegram-bot-api/telegram-bot-api](https://github.com/go-telegram-bot-api/telegram-bot-api)
|
- Telegram support: [go-telegram-bot-api/telegram-bot-api](https://github.com/go-telegram-bot-api/telegram-bot-api)
|
||||||
- Twitter: [dghubble/go-twitter](https://github.com/dghubble/go-twitter)
|
- Twitter: [dghubble/go-twitter](https://github.com/dghubble/go-twitter)
|
||||||
|
- WeChat: [silenceper/wechat](https://github.com/silenceper/wechat)
|
||||||
- WhatsApp: [Rhymen/go-whatsapp](https://github.com/Rhymen/go-whatsapp)
|
- WhatsApp: [Rhymen/go-whatsapp](https://github.com/Rhymen/go-whatsapp)
|
||||||
|
|
||||||
## Author <a id="author"></a>
|
## Author <a id="author"></a>
|
||||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 100 KiB |
6
go.mod
6
go.mod
@ -6,7 +6,7 @@ require (
|
|||||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
|
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
|
||||||
github.com/Rhymen/go-whatsapp v0.1.1
|
github.com/Rhymen/go-whatsapp v0.1.1
|
||||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60
|
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60
|
||||||
github.com/atc0005/go-teams-notify/v2 v2.4.2
|
github.com/atc0005/go-teams-notify/v2 v2.5.0
|
||||||
github.com/aws/aws-sdk-go-v2 v1.3.4
|
github.com/aws/aws-sdk-go-v2 v1.3.4
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.1.6
|
github.com/aws/aws-sdk-go-v2/config v1.1.6
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.1.6
|
github.com/aws/aws-sdk-go-v2/credentials v1.1.6
|
||||||
@ -21,7 +21,7 @@ require (
|
|||||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/line/line-bot-sdk-go v7.8.0+incompatible
|
github.com/line/line-bot-sdk-go v7.8.0+incompatible
|
||||||
github.com/mailgun/mailgun-go/v4 v4.4.1
|
github.com/mailgun/mailgun-go/v4 v4.5.1
|
||||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
@ -29,7 +29,7 @@ require (
|
|||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/plivo/plivo-go v5.5.2+incompatible
|
github.com/plivo/plivo-go v5.5.2+incompatible
|
||||||
github.com/sendgrid/rest v2.6.3+incompatible // indirect
|
github.com/sendgrid/rest v2.6.3+incompatible // indirect
|
||||||
github.com/sendgrid/sendgrid-go v3.8.0+incompatible
|
github.com/sendgrid/sendgrid-go v3.9.0+incompatible
|
||||||
github.com/silenceper/wechat/v2 v2.0.5
|
github.com/silenceper/wechat/v2 v2.0.5
|
||||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
||||||
|
15
go.sum
15
go.sum
@ -13,8 +13,8 @@ github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf
|
|||||||
github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM=
|
github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM=
|
||||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 h1:prBTRx78AQnXzivNT9Crhu564W/zPPr3ibSlpT9xKcE=
|
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 h1:prBTRx78AQnXzivNT9Crhu564W/zPPr3ibSlpT9xKcE=
|
||||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60/go.mod h1:rjP7sIipbZcagro/6TCk6X0ZeFT2eyudH5+fve/cbBA=
|
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60/go.mod h1:rjP7sIipbZcagro/6TCk6X0ZeFT2eyudH5+fve/cbBA=
|
||||||
github.com/atc0005/go-teams-notify/v2 v2.4.2 h1:3KQ8e8LN4kwuWWHpnCNTXA15JdLRaNWcCS1VS0a4SO0=
|
github.com/atc0005/go-teams-notify/v2 v2.5.0 h1:WKkrbYe2gfT76rltlWTjg8Eukvz0tvzAqs2jyC3pQe0=
|
||||||
github.com/atc0005/go-teams-notify/v2 v2.4.2/go.mod h1:BSlh1HBcgWcGoNM3Abm36WMPcj+k8Wf0ZLZx6lBx2qk=
|
github.com/atc0005/go-teams-notify/v2 v2.5.0/go.mod h1:BSlh1HBcgWcGoNM3Abm36WMPcj+k8Wf0ZLZx6lBx2qk=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.3.2/go.mod h1:7OaACgj2SX3XGWnrIjGlJM22h6yD6MEWKvm7levnnM8=
|
github.com/aws/aws-sdk-go-v2 v1.3.2/go.mod h1:7OaACgj2SX3XGWnrIjGlJM22h6yD6MEWKvm7levnnM8=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.3.4 h1:+XY8285OZTxWstzoHHvMewMULowmFSUs2PnU31OSr9I=
|
github.com/aws/aws-sdk-go-v2 v1.3.4 h1:+XY8285OZTxWstzoHHvMewMULowmFSUs2PnU31OSr9I=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.3.4/go.mod h1:7OaACgj2SX3XGWnrIjGlJM22h6yD6MEWKvm7levnnM8=
|
github.com/aws/aws-sdk-go-v2 v1.3.4/go.mod h1:7OaACgj2SX3XGWnrIjGlJM22h6yD6MEWKvm7levnnM8=
|
||||||
@ -24,14 +24,17 @@ github.com/aws/aws-sdk-go-v2/credentials v1.1.6 h1:efaeh6FsO/jzyJ+U4ZxduKC6rRJDr
|
|||||||
github.com/aws/aws-sdk-go-v2/credentials v1.1.6/go.mod h1:q1wQ5jHdFNhc4wnNcOEpnovs4keJA5Ds+qESCnfEsgU=
|
github.com/aws/aws-sdk-go-v2/credentials v1.1.6/go.mod h1:q1wQ5jHdFNhc4wnNcOEpnovs4keJA5Ds+qESCnfEsgU=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.6 h1:zoOz5V56jO/rGixsCDnrQtAzYRYM2hGA/43U6jVMFbo=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.6 h1:zoOz5V56jO/rGixsCDnrQtAzYRYM2hGA/43U6jVMFbo=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.6/go.mod h1:0+fWMitrmIpENiY8/1DyhdYPUCAPvd9UNz9mtCsEoLQ=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.6/go.mod h1:0+fWMitrmIpENiY8/1DyhdYPUCAPvd9UNz9mtCsEoLQ=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.3/go.mod h1:C50Z41fJaJ7WgaeeCulOGAU3q4+4se4B3uOPFdhBi2I=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.6 h1:ldYIsOP4WyjdzW8t6RC/aSieajrlx+3UN3UCZy1KM5Y=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.6 h1:ldYIsOP4WyjdzW8t6RC/aSieajrlx+3UN3UCZy1KM5Y=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.6/go.mod h1:L0KWr0ASo83PRZu9NaZaDsw3koS6PspKv137DMDZjHo=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.6/go.mod h1:L0KWr0ASo83PRZu9NaZaDsw3koS6PspKv137DMDZjHo=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ses v1.2.2 h1:NVHy0deH7YK3yJc+xB1gA/wZeNXWVtL4zOTSdj5spfI=
|
github.com/aws/aws-sdk-go-v2/service/ses v1.2.2 h1:NVHy0deH7YK3yJc+xB1gA/wZeNXWVtL4zOTSdj5spfI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ses v1.2.2/go.mod h1:fdj/PsFS59GndzkUKAuWw7cLOjgLHn+V8V6otywinUk=
|
github.com/aws/aws-sdk-go-v2/service/ses v1.2.2/go.mod h1:fdj/PsFS59GndzkUKAuWw7cLOjgLHn+V8V6otywinUk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.1.5 h1:B7ec5wE4+3Ldkurmq0C4gfQFtElGTG+/iTpi/YPMzi4=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.1.5 h1:B7ec5wE4+3Ldkurmq0C4gfQFtElGTG+/iTpi/YPMzi4=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.1.5/go.mod h1:bpGz0tidC4y39sZkQSkpO/J0tzWCMXHbw6FZ0j1GkWM=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.1.5/go.mod h1:bpGz0tidC4y39sZkQSkpO/J0tzWCMXHbw6FZ0j1GkWM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.1.2/go.mod h1:zu7rotIY9P4Aoc6ytqLP9jeYrECDHUODB5Gbp+BSHl8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.3.0 h1:4o69U9waE25xhRbsnXa4jjQac03BFJcNfcZkSedk3e4=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.3.0 h1:4o69U9waE25xhRbsnXa4jjQac03BFJcNfcZkSedk3e4=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.3.0/go.mod h1:ssRzzJ2RZOVuKj2Vx1YE7ypfil/BIlgmQnCSW4DistU=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.3.0/go.mod h1:ssRzzJ2RZOVuKj2Vx1YE7ypfil/BIlgmQnCSW4DistU=
|
||||||
|
github.com/aws/smithy-go v1.2.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||||
github.com/aws/smithy-go v1.3.1 h1:xJFO4pK0y9J8fCl34uGsSJX5KNnGbdARDlA5BPhXnwE=
|
github.com/aws/smithy-go v1.3.1 h1:xJFO4pK0y9J8fCl34uGsSJX5KNnGbdARDlA5BPhXnwE=
|
||||||
github.com/aws/smithy-go v1.3.1/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
github.com/aws/smithy-go v1.3.1/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
|
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
|
||||||
@ -126,8 +129,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/line/line-bot-sdk-go v7.8.0+incompatible h1:Uf9/OxV0zCVfqyvwZPH8CrdiHXXmMRa/L91G3btQblQ=
|
github.com/line/line-bot-sdk-go v7.8.0+incompatible h1:Uf9/OxV0zCVfqyvwZPH8CrdiHXXmMRa/L91G3btQblQ=
|
||||||
github.com/line/line-bot-sdk-go v7.8.0+incompatible/go.mod h1:0RjLjJEAU/3GIcHkC3av6O4jInAbt25nnZVmOFUgDBg=
|
github.com/line/line-bot-sdk-go v7.8.0+incompatible/go.mod h1:0RjLjJEAU/3GIcHkC3av6O4jInAbt25nnZVmOFUgDBg=
|
||||||
github.com/mailgun/mailgun-go/v4 v4.4.1 h1:b58b7a5QZSTkfaE89OeN0dXzcY+HyJXOfalvuSDL1Q8=
|
github.com/mailgun/mailgun-go/v4 v4.5.1 h1:XrQQ/ZgqFvINRKy+eBqowLl7k3pQO6OCLpKphliMOFs=
|
||||||
github.com/mailgun/mailgun-go/v4 v4.4.1/go.mod h1:FJlF9rI5cQT+mrwujtJjPMbIVy3Ebor9bKTVsJ0QU40=
|
github.com/mailgun/mailgun-go/v4 v4.5.1/go.mod h1:FJlF9rI5cQT+mrwujtJjPMbIVy3Ebor9bKTVsJ0QU40=
|
||||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
@ -165,8 +168,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/sendgrid/rest v2.6.3+incompatible h1:h/uruXAzKxVyDDIQX/MkQI73p/gsdpEnb5q2wxSvTsA=
|
github.com/sendgrid/rest v2.6.3+incompatible h1:h/uruXAzKxVyDDIQX/MkQI73p/gsdpEnb5q2wxSvTsA=
|
||||||
github.com/sendgrid/rest v2.6.3+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE=
|
github.com/sendgrid/rest v2.6.3+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE=
|
||||||
github.com/sendgrid/sendgrid-go v3.8.0+incompatible h1:7yoUFMwT+jDI2ArBpC6zvtuQj1RUyYfCDl7zZea3XV4=
|
github.com/sendgrid/sendgrid-go v3.9.0+incompatible h1:rs5T2u6XVNDN51Z8uynH+vgKLgCem+xfuL1OMcxsmBE=
|
||||||
github.com/sendgrid/sendgrid-go v3.8.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
|
github.com/sendgrid/sendgrid-go v3.9.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8=
|
||||||
github.com/silenceper/wechat/v2 v2.0.5 h1:yBOeTMiMAzCAvmhR14ADMlrRrR3oOqmoz7I/bus7bTw=
|
github.com/silenceper/wechat/v2 v2.0.5 h1:yBOeTMiMAzCAvmhR14ADMlrRrR3oOqmoz7I/bus7bTw=
|
||||||
github.com/silenceper/wechat/v2 v2.0.5/go.mod h1:hksYXWXGl7/E6TQojFNgxv8ouTF9CPPjfvWWJouJJGs=
|
github.com/silenceper/wechat/v2 v2.0.5/go.mod h1:hksYXWXGl7/E6TQojFNgxv8ouTF9CPPjfvWWJouJJGs=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
|
84
service/wechat/README.md
Normal file
84
service/wechat/README.md
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# WeChat
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
To use the service you need to apply for a [WeChat Official Account](https://mp.weixin.qq.com).
|
||||||
|
Application approval is a manual process and might take a while. In the meantime, you
|
||||||
|
can test your code using the [sandbox](https://developers.weixin.qq.com/sandbox).
|
||||||
|
|
||||||
|
You need the following configuration information to sent out text messages with an Official Account:
|
||||||
|
|
||||||
|
1. AppID
|
||||||
|
2. AppSecret
|
||||||
|
3. Token
|
||||||
|
4. EncodingAESKey
|
||||||
|
5. Verification URL
|
||||||
|
|
||||||
|
The `AppID` and `AppSecret` are provided to you by WeChat. The `Token`, `EncodingAESKey` and
|
||||||
|
the Verifications URL, you set yourself and are needed by the authentication method. More on
|
||||||
|
this [here](https://developers.weixin.qq.com/doc/offiaccount/en/Basic_Information/Access_Overview.html).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
Until your application is approved, sign in to the sandbox to get an `AppID`, an `AppSecret` and
|
||||||
|
set the `Token` and the Verification URL. Typically, you need a service like [ngrok](https://ngrok.com/)
|
||||||
|
for the latter. You don't need to/cannot set the `EncodingAESKey`, because it's not required in the
|
||||||
|
sandbox environment:
|
||||||
|
|
||||||
|
![wechat_sandbox_1.png](img/wechat_sandbox_1.png)
|
||||||
|
|
||||||
|
You also need a user subscribed to your Official Account. You can use your own:
|
||||||
|
|
||||||
|
![wechat_sandbox_2.png](img/wechat_sandbox_2.png)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/silenceper/wechat/v2/cache"
|
||||||
|
"log"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"github.com/nikoksr/notify"
|
||||||
|
"github.com/nikoksr/notify/service/wechat"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
wechatSvc := wechat.New(&wechat.Config{
|
||||||
|
AppID: "abcdefghi",
|
||||||
|
AppSecret: "jklmnopqr",
|
||||||
|
Token: "mytoken",
|
||||||
|
EncodingAESKey: "IGNORED-IN-SANDBOX",
|
||||||
|
Cache: cache.NewMemory(),
|
||||||
|
})
|
||||||
|
|
||||||
|
// do this only once, or when settings are updated
|
||||||
|
devMode := true
|
||||||
|
wechatSvc.WaitForOneOffVerification(":7999", devMode, func(r *http.Request, verified bool) {
|
||||||
|
if !verified {
|
||||||
|
fmt.Println("unknown or failed verification call")
|
||||||
|
} else {
|
||||||
|
fmt.Println("verification call done")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
wechatSvc.AddReceivers("some-user-openid")
|
||||||
|
|
||||||
|
notifier := notify.New()
|
||||||
|
notifier.UseServices(wechatSvc)
|
||||||
|
|
||||||
|
err := notifier.Send(context.Background(), "subject", "message")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("notifier.Send() failed: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("notification sent")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
![wechat_usage.png](img/wechat_usage.png)
|
||||||
|
|
BIN
service/wechat/img/wechat_sandbox_1.png
Normal file
BIN
service/wechat/img/wechat_sandbox_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
BIN
service/wechat/img/wechat_sandbox_2.png
Normal file
BIN
service/wechat/img/wechat_sandbox_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
BIN
service/wechat/img/wechat_usage.png
Normal file
BIN
service/wechat/img/wechat_usage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.7 KiB |
27
service/wechat/mock_wechatMessageManager.go
Normal file
27
service/wechat/mock_wechatMessageManager.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Code generated by mockery 2.7.4. DO NOT EDIT.
|
||||||
|
|
||||||
|
package wechat
|
||||||
|
|
||||||
|
import (
|
||||||
|
message "github.com/silenceper/wechat/v2/officialaccount/message"
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mockWechatMessageManager is an autogenerated mock type for the wechatMessageManager type
|
||||||
|
type mockWechatMessageManager struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send provides a mock function with given fields: msg
|
||||||
|
func (_m *mockWechatMessageManager) Send(msg *message.CustomerMessage) error {
|
||||||
|
ret := _m.Called(msg)
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*message.CustomerMessage) error); ok {
|
||||||
|
r0 = rf(msg)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
145
service/wechat/wechat.go
Normal file
145
service/wechat/wechat.go
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
package wechat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/silenceper/wechat/v2"
|
||||||
|
"github.com/silenceper/wechat/v2/cache"
|
||||||
|
"github.com/silenceper/wechat/v2/officialaccount/config"
|
||||||
|
"github.com/silenceper/wechat/v2/officialaccount/message"
|
||||||
|
"github.com/silenceper/wechat/v2/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type verificationCallbackFunc func(r *http.Request, verified bool)
|
||||||
|
|
||||||
|
// Config is the Service configuration.
|
||||||
|
type Config struct {
|
||||||
|
AppID string
|
||||||
|
AppSecret string
|
||||||
|
Token string
|
||||||
|
EncodingAESKey string
|
||||||
|
Cache cache.Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
// wechatMessageManager abstracts go-wechat's message.Manager for writing unit tests
|
||||||
|
type wechatMessageManager interface {
|
||||||
|
Send(msg *message.CustomerMessage) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service encapsulates the WeChat client along with internal state for storing users.
|
||||||
|
type Service struct {
|
||||||
|
config *Config
|
||||||
|
messageManager wechatMessageManager
|
||||||
|
userIDs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new instance of a WeChat notification service.
|
||||||
|
func New(cfg *Config) *Service {
|
||||||
|
wc := wechat.NewWechat()
|
||||||
|
wcCfg := &config.Config{
|
||||||
|
AppID: cfg.AppID,
|
||||||
|
AppSecret: cfg.AppSecret,
|
||||||
|
Token: cfg.Token,
|
||||||
|
EncodingAESKey: cfg.EncodingAESKey,
|
||||||
|
Cache: cfg.Cache,
|
||||||
|
}
|
||||||
|
|
||||||
|
oa := wc.GetOfficialAccount(wcCfg)
|
||||||
|
|
||||||
|
return &Service{
|
||||||
|
config: cfg,
|
||||||
|
messageManager: oa.GetCustomerMessageManager(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForOneOffVerification waits for the verification call from the WeChat backend.
|
||||||
|
//
|
||||||
|
// Should be running when (re-)applying settings in wechat configuration.
|
||||||
|
//
|
||||||
|
// Set devMode to true when using the sandbox.
|
||||||
|
//
|
||||||
|
// See https://developers.weixin.qq.com/doc/offiaccount/en/Basic_Information/Access_Overview.html
|
||||||
|
func (s *Service) WaitForOneOffVerification(serverURL string, devMode bool, callback verificationCallbackFunc) error {
|
||||||
|
srv := &http.Server{Addr: serverURL}
|
||||||
|
verificationDone := &sync.WaitGroup{}
|
||||||
|
verificationDone.Add(1)
|
||||||
|
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
query := r.URL.Query()
|
||||||
|
|
||||||
|
echoStr := query.Get("echostr")
|
||||||
|
if devMode {
|
||||||
|
if callback != nil {
|
||||||
|
callback(r, true)
|
||||||
|
}
|
||||||
|
_, _ = w.Write([]byte(echoStr))
|
||||||
|
// verification done; dev mode
|
||||||
|
verificationDone.Done()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform signature check
|
||||||
|
timestamp := query.Get("timestamp")
|
||||||
|
nonce := query.Get("nonce")
|
||||||
|
suppliedSignature := query.Get("signature")
|
||||||
|
computedSignature := util.Signature(s.config.Token, timestamp, nonce)
|
||||||
|
if suppliedSignature == computedSignature {
|
||||||
|
if callback != nil {
|
||||||
|
callback(r, true)
|
||||||
|
}
|
||||||
|
_, _ = w.Write([]byte(echoStr))
|
||||||
|
// verification done; prod mode
|
||||||
|
verificationDone.Done()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// verification not done (keep waiting)
|
||||||
|
if callback != nil {
|
||||||
|
callback(r, false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var err error
|
||||||
|
go func() {
|
||||||
|
if innerErr := srv.ListenAndServe(); innerErr != http.ErrServerClosed {
|
||||||
|
err = errors.Wrapf(innerErr, "failed to start verification listener '%s'", serverURL)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// wait until verification is done and shutdown the server
|
||||||
|
verificationDone.Wait()
|
||||||
|
|
||||||
|
if innerErr := srv.Shutdown(context.TODO()); innerErr != nil {
|
||||||
|
err = errors.Wrap(innerErr, "failed to shutdown verification listerer")
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddReceivers takes user ids and adds them to the internal users list. The Send method will send
|
||||||
|
// a given message to all those users.
|
||||||
|
func (s *Service) AddReceivers(userIDs ...string) {
|
||||||
|
s.userIDs = append(s.userIDs, userIDs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send takes a message subject and a message content and sends them to all previously set users.
|
||||||
|
func (s *Service) Send(ctx context.Context, subject, content string) error {
|
||||||
|
for _, userID := range s.userIDs {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
text := fmt.Sprintf("%s\n%s", subject, content)
|
||||||
|
err := s.messageManager.Send(message.NewCustomerTextMessage(userID, text))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to send message to WeChat user '%s'", userID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
53
service/wechat/wechat_test.go
Normal file
53
service/wechat/wechat_test.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package wechat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/silenceper/wechat/v2/officialaccount/message"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddReceivers(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
|
||||||
|
svc := &Service{
|
||||||
|
userIDs: []string{},
|
||||||
|
}
|
||||||
|
userIDs := []string{"User1ID", "User2ID", "User3ID"}
|
||||||
|
svc.AddReceivers(userIDs...)
|
||||||
|
|
||||||
|
assert.Equal(svc.userIDs, userIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSend(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
|
||||||
|
svc := &Service{
|
||||||
|
userIDs: []string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// test wechat message manager returning error
|
||||||
|
mockMsgManager := new(mockWechatMessageManager)
|
||||||
|
mockMsgManager.On("Send", message.NewCustomerTextMessage("UserID1", "subject\nmessage")).
|
||||||
|
Return(errors.New("some error"))
|
||||||
|
svc.messageManager = mockMsgManager
|
||||||
|
svc.AddReceivers("UserID1")
|
||||||
|
ctx := context.Background()
|
||||||
|
err := svc.Send(ctx, "subject", "message")
|
||||||
|
assert.NotNil(err)
|
||||||
|
mockMsgManager.AssertExpectations(t)
|
||||||
|
|
||||||
|
// test success and multiple receivers
|
||||||
|
mockMsgManager = new(mockWechatMessageManager)
|
||||||
|
mockMsgManager.On("Send", message.NewCustomerTextMessage("UserID1", "subject\nmessage")).
|
||||||
|
Return(nil)
|
||||||
|
mockMsgManager.On("Send", message.NewCustomerTextMessage("UserID2", "subject\nmessage")).
|
||||||
|
Return(nil)
|
||||||
|
svc.messageManager = mockMsgManager
|
||||||
|
svc.AddReceivers("UserID1", "UserID2")
|
||||||
|
err = svc.Send(ctx, "subject", "message")
|
||||||
|
assert.Nil(err)
|
||||||
|
mockMsgManager.AssertExpectations(t)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user