├── .dockerignore ├── .github └── workflows │ └── test.yml ├── .gitignore ├── Dockerfile ├── README.md ├── action.yml ├── getuserList.js ├── package.json ├── wework.sh └── yarn.lock /.dockerignore: -------------------------------------------------------------------------------- 1 | .git -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - 12 | name: test send message 13 | uses: ntfs32/wework@master 14 | with: 15 | WEWORK_USERLIST: ${{ secrets.WEWORK_USERLIST }} 16 | WEWORK_CORPID: ${{ secrets.WEWORK_CORPID }} 17 | WEWORK_AGENTID: ${{ secrets.WEWORK_AGENTID }} 18 | WEWORK_APPSECRET: ${{ secrets.WEWORK_APPSECRET }} 19 | WEWORK_TOUSER: "shaddock" 20 | WEWORK_CONTENT: "thsi is a test" 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | test.sh 2 | node_modules -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.12 2 | LABEL maintainer="shaddock" 3 | 4 | 5 | RUN \ 6 | sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \ 7 | apk add --no-cache \ 8 | jq bash curl 9 | 10 | ADD wework.sh /opt/wework.sh 11 | 12 | CMD [ "/opt/wework.sh" ] 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Send message to Enterprise WeChat 2 | 3 | ### All envionment variables 4 | 5 | - WEWORK_TOUSER = amy|jack 6 | - WEWORK_CONTENT = "you have a new message..." 7 | - WEWORK_AGENTID = 1000001 8 | - WEWORK_APPSECRET = tTdO5Nn9IBG4iPxxxxxxw0nUTyDF_OrXsUwwbogY 9 | - WEWORK_CORPID = ww1efaxxxxxxxb24df 10 | - WEWORK_USERLIST = [{"name":"amy","userid":"32ee8a9a5d9c6bd2b15c8cf2cba7ba01"},{"name":"jack","userid":"c9ab9a30645f85e07c3f176d21b6c220"}] 11 | 12 | 13 | 14 | ### How to get enterprise wechat userlist 15 | 16 | - Due to the limit of obtaining token times, we must get user list before use this action, run script `export WEWORK_CORPID=xxx && export WEWORK_APPSECRET=xxxx && node ./getuserList.js` 17 | 18 | ### Used for Github Actions 19 | ``` yaml 20 | name: ci 21 | on: 22 | push: 23 | branches: master 24 | jobs: 25 | test: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - 29 | name: test send message 30 | uses: ntfs32/wework@v0.1.0-alpha 31 | with: 32 | WEWORK_USERLIST: ${{ secrets.WEWORK_USERLIST }} 33 | WEWORK_CORPID: ${{ secrets.WEWORK_CORPID }} 34 | WEWORK_AGENTID: ${{ secrets.WEWORK_AGENTID }} 35 | WEWORK_APPSECRET: ${{ secrets.WEWORK_APPSECRET }} 36 | WEWORK_TOUSER: "shaddock" 37 | WEWORK_CONTENT: "thsi is a test" 38 | 39 | ``` 40 | 41 | ### Used for Gitlab Ci 42 | 43 | 1. update gitlab group CI / CD Settings -> Variables 44 | - WEWORK_AGENTID = 1000001 45 | - WEWORK_APPSECRET = tTdO5Nn9IBG4iPxxxxxxw0nUTyDF_OrXsUwwbogY 46 | - WEWORK_CORPID = ww1efaxxxxxxxb24df 47 | - WEWORK_USERLIST = [{"name":"amy","userid":"32ee8a9a5d9c6bd2b15c8cf2cba7ba01"},{"name":"jack","userid":"c9ab9a30645f85e07c3f176d21b6c220"}] 48 | 49 | 2. update `gitlab-ci.yml` 50 | 51 | ``` yaml 52 | deploy_notices: 53 | image: 54 | name: notices/wework:2.0 55 | stage:deploy 56 | only: 57 | - tags 58 | script: 59 | - export WEWORK_TOUSER="amy|jack 60 | - export WEWORK_CONTENT="$CI_PROJECT_NAME release sunccess, docker image: $IMAGE_NAME:$CI_COMMIT_TAG" 61 | - /opt/wework.sh 62 | 63 | ``` 64 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'WeChat Enterprise App Messages' 2 | description: 'Github Action for Sending Wechat Enterprise App messages' 3 | author: 'shaddock ' 4 | inputs: 5 | WEWORK_APPSECRET: 6 | description: 'Wechat app secret' 7 | WEWORK_AGENTID: 8 | description: 'Wechat agentid' 9 | default: "markdown" 10 | WEWORK_CORPID: 11 | description: 'Wechat corpid' 12 | WEWORK_USERLIST: 13 | description: 'message userlist' 14 | default: '[{"name":"张三","userid":"32ee8a9a5d9c6bd2b15c8cf2cba7ba01"}]' 15 | WEWORK_CONTENT: 16 | description: 'message content' 17 | WEWORK_TOUSER: 18 | description: 'username in userlist' 19 | default: '张三' 20 | runs: 21 | using: 'docker' 22 | image: 'Dockerfile' 23 | 24 | branding: 25 | color: "blue" 26 | icon: "message-square" 27 | -------------------------------------------------------------------------------- /getuserList.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | const corpId = process.env.WEWORK_CORPID; 4 | const corpSecret = process.env.WEWORK_APPSECRET; 5 | const agentId = process.env.WEWORK_AGENTID; 6 | async function getAccessToken(corpid, corpsecret) { 7 | return axios.get(`https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${corpsecret}`).then(res => res.data.access_token ).catch(err => { 8 | console.log('get access_tokentoken failed'); 9 | return ''; 10 | }) 11 | } 12 | 13 | async function getDepartmentList(accessToken) { 14 | return axios.get(`https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=${accessToken}`).then(res =>{ 15 | return res.data.department; 16 | }).catch(err => { 17 | console.log('get departmentList failed'); 18 | return []; 19 | }) 20 | } 21 | 22 | async function getUserlist(accessToken, departmentId, getchild = true) { 23 | return axios.get(`https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token=${accessToken}&department_id=${departmentId}&fetch_child=${getchild}`).then(res => { 24 | return res.data.userlist; 25 | }).catch(err => { 26 | console.log('get departmentList failed'); 27 | return []; 28 | }) 29 | } 30 | 31 | (async function() { 32 | const accessToken = await getAccessToken(corpId, corpSecret); 33 | const departmentList = await getDepartmentList(accessToken); 34 | let userList = []; 35 | for (let dep in departmentList) { 36 | userList.push(...await getUserlist(accessToken, departmentList[dep].id)) 37 | } 38 | console.log(JSON.stringify(userList.map(item => { 39 | return { 40 | name: item.name, 41 | userid: item.userid, 42 | } 43 | }))) 44 | })(); 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "axios": "^0.21.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /wework.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # shell调用企业微信发送消息命令 4 | # ./weowrk.sh ${人员} "消息" 5 | # 例: 6 | # ./wework.sh @all "hello!" 7 | # ./wework.sh maYun "hello!" 8 | # 注: 9 | # 消息中可以使用"\n"表示换行; 10 | # 消息中不可以使用空格; 11 | 12 | # 微信接口参数 13 | # 根据自己申请的企业微信上接口参数调整; 14 | corpid=$WEWORK_CORPID 15 | corpid=${corpid:-${INPUT_WEWORK_CORPID}} 16 | appsecret=$WEWORK_APPSECRET 17 | appsecret=-${appsecret:-${INPUT_WEWORK_APPSECRET}} 18 | agentid=$WEWORK_AGENTID 19 | agentid=${agentid:-${INPUT_WEWORK_AGENTID}} 20 | 21 | # 用户列表 22 | # 格式: [{"name":"testuser1","userid":"31ee8a9e9d1d67d2b15c87f7cba7ea0a"}] 23 | userList=$WEWORK_USERLIST 24 | userList=${userList:-${INPUT_WEWORK_USERLIST}} 25 | userList=${userList:-'[]'} 26 | 27 | #部门列表 28 | # 格式: [{"name":"department1","partyid":"c2ee8a1e9d9d6bc2b15c8cf2cba7ea00"}] 29 | partyList=$WEWORK_PARTYLIST 30 | partyList=${partyList:-${INPUT_WEWORK_PARTYLIST}} 31 | partyList=${partyList:-'[]'} 32 | 33 | # 消息接收用户,使用|分割的用户id列表 34 | touser=${WEWORK_TOUSER} 35 | touser=-${touser:-${INPUT_WEWORK_TOUSER}} 36 | 37 | # 消息接收部门,使用|分割的部分id列表 38 | toparty=${WEWORK_toparty} 39 | toparty=-${toparty:-${INPUT_WEWORK_toparty}} 40 | 41 | 42 | # 消息内容 43 | content=${WEWORK_CONTENT} 44 | content=${content:-${INPUT_WEWORK_CONTENT}} 45 | 46 | msgtype=${WEWORK_MSGTYPE:-'markdown'} 47 | 48 | if [ -z "$corpid" -o -z "$appsecret" -o -z "$agentid" ]; then 49 | echo "未设置企业微信应用相关消息" 50 | echo "env[ WEWORK_CORPID, WEWORK_APPSECRET, WEWORK_AGENTID ]不能为空" 51 | exit 1; 52 | fi 53 | 54 | if [ -z "$touser" -a -z "$toparty" ];then 55 | echo "未设置消息接受者相关消息" 56 | echo "env[ WEWORK_TOUSER, WEWORK_TOPARTY ]不能为空" 57 | exit 1; 58 | fi 59 | 60 | if [ -z "$content" ];then 61 | echo "未设置发送消息体" 62 | echo "env[ WEWORK_CONTENT ]不能为空" 63 | exit 1; 64 | fi 65 | 66 | if [ "$userList" != '[]' ];then 67 | OLD_IFS="$IFS" 68 | IFS="|" 69 | echo $touser 70 | templist=($touser) 71 | IFS="$OLD_IFS" 72 | touser= 73 | for u in ${templist[@]} 74 | do 75 | userid=$(echo $userList | jq 'map(select(.name == "'$u'"))'| jq -r .[].userid); 76 | if [ ! -z "$touser" ];then 77 | touser=$touser"|$userid"; 78 | else 79 | touser=$userid; 80 | fi 81 | done 82 | fi 83 | 84 | 85 | if [ "$partyList" != '[]' ];then 86 | OLD_IFS="$IFS" 87 | IFS="|" 88 | templist=($toparty) 89 | IFS="$OLD_IFS" 90 | toparty= 91 | for u in ${templist[@]} 92 | do 93 | partyid=$(echo $userList | jq 'map(select(.name == "'$u'"))'| jq -r .[].partyid); 94 | if [ ! -z "$toparty" ];then 95 | toparty=$toparty"|$partyid"; 96 | else 97 | toparty=$partyid; 98 | fi 99 | done 100 | fi 101 | 102 | if [ -z "$touser" -a -z "$toparty" ];then 103 | echo "未设置消息接受者相关消息" 104 | echo "请检查发送参数env[WEWORK_USERLIST, WEWORK_TOPARTY, WEWORK_TOUSER, WEWORK_PARTYLIST]" 105 | exit 1; 106 | fi 107 | 108 | #获取accesstoken 109 | accesstoken=$(/usr/bin/curl -sSl https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}\&corpsecret=${appsecret}| jq -r '.access_token') 110 | #发送消息 111 | # echo $accesstoken 112 | msgsend_url="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${accesstoken}" 113 | json_params="{\"touser\":\"${touser}\",\"toparty\":\"${toparty}\",\"msgtype\":\"${msgtype}\",\"agentid\":\"${agentid}\",\"${msgtype}\":{\"content\":\"${content}\"},\"safe\":\"0\"}" 114 | echo $json_params 115 | curl -sSl -XPOST -d "${json_params}" "${msgsend_url}" 116 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | axios@^0.21.1: 6 | version "0.21.1" 7 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" 8 | integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== 9 | dependencies: 10 | follow-redirects "^1.10.0" 11 | 12 | follow-redirects@^1.10.0: 13 | version "1.13.1" 14 | resolved "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.13.1.tgz?cache=0&sync_timestamp=1607916833378&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7" 15 | integrity sha1-X2m4Ezds7k/QR0o6uoNd8Eq3Y7c= 16 | --------------------------------------------------------------------------------