-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
826 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.DS_Store | ||
/.vscode | ||
/test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package workapi | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
// GetAgent 通过agentid获取企业微信应用信息 | ||
func (wx *WorkAPI) GetAgent(agentID int) ([]byte, error) { | ||
token, err := wx.GetTokenString() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
url := BaseURL + fmt.Sprintf(WorkAPIType["AgentGet"][0], token, agentID) | ||
|
||
body, err := HTTPRequest(url, WorkAPIType["AgentGet"][1], nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return body, nil | ||
} | ||
|
||
// GetAgentList 通过agentid获取企业微信应用信息 | ||
func (wx *WorkAPI) GetAgentList() ([]byte, error) { | ||
token, err := wx.GetTokenString() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
url := BaseURL + fmt.Sprintf(WorkAPIType["AgentGetList"][0], token) | ||
|
||
body, err := HTTPRequest(url, WorkAPIType["AgentGetList"][1], nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return body, nil | ||
} | ||
|
||
// SetAgent 设置企业微信应用信息 | ||
func (wx *WorkAPI) SetAgent(agent Agent) ([]byte, error) { | ||
token, err := wx.GetTokenString() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
url := BaseURL + fmt.Sprintf(WorkAPIType["AgentSet"][0], token) | ||
|
||
data, err := DataToReader(agent) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
body, err := HTTPRequest(url, WorkAPIType["AgentSet"][1], data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return body, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package workapi | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/json-iterator/go" | ||
|
||
cache "github.com/patrickmn/go-cache" | ||
) | ||
|
||
// WorkAPI 企业微信 | ||
type WorkAPI struct { | ||
CorpID string | ||
AppSecret string | ||
AppID int | ||
TokenCache *cache.Cache | ||
} | ||
|
||
// AccessToken 企业微信应用令牌信息 | ||
type accessToken struct { | ||
AccessToken string `json:"access_token"` | ||
ExpiresIn int64 `json:"expires_in"` //秒 默认返回是2小时 | ||
ExpireAt int64 `json:"expireAt"` //在什么时候过期 | ||
ErrCode int `json:"errcode"` | ||
ErrMsg string `json:"errmsg"` | ||
} | ||
|
||
// BaseURL 企业微信应用接口调用链接 | ||
const BaseURL = "https://qyapi.weixin.qq.com" | ||
|
||
// WorkAPIType 微信API链接与连接模式 | ||
var WorkAPIType = map[string][]string{ | ||
"GetAccessToken": {"/cgi-bin/gettoken?corpid=%s&corpsecret=%s", "GET"}, | ||
"UserCreaet": {"/cgi-bin/user/create?access_token=%s", "POST"}, | ||
"UserGet": {"/cgi-bin/user/get?access_token=%s&userid=%s", "GET"}, | ||
"UserUpdate": {"/cgi-bin/user/update?access_token=%s", "POST"}, | ||
"UserDelete": {"/cgi-bin/user/delete?access_token=%s", "GET"}, | ||
"UserBatchDelete": {"/cgi-bin/user/batchdelete?access_token=%s", "POST"}, | ||
"UserSimpleList": {"/cgi-bin/user/simplelist?access_token=%s&department_id=%v&fetch_child=%v", "GET"}, | ||
"UserList": {"/cgi-bin/user/list?access_token=%s&department_id=%v&fetch_child=%v", "GET"}, | ||
"UserIDToOpenID": {"/cgi-bin/user/convert_to_openid?access_token=%s", "POST"}, | ||
"OpenIDToUserID": {"/cgi-bin/user/convert_to_userid?access_token=%s", "POST"}, | ||
"UserAuthSuccess": {"/cgi-bin/user/authsucc?access_token=%s", "GET"}, | ||
|
||
"DepartmentCreaet": {"/cgi-bin/department/create?access_token=%s", "POST"}, | ||
"DepartmentGet": {"/cgi-bin/department/get?access_token=%s&id=%v", "POST"}, | ||
"DepartmentUpdate": {"/cgi-bin/department/update?access_token=%s", "POST"}, | ||
"DepartmentDelete": {"/cgi-bin/department/delete?access_token=%s&id=%v", "GET"}, | ||
"DepartmentList": {"/cgi-bin/department/list?access_token=%s", "GET"}, | ||
|
||
"TagCreate": {"/cgi-bin/tag/create?access_token=%s", "POST"}, | ||
"TagUpdate": {"/cgi-bin/tag/update?access_token=%s", "POST"}, | ||
"TagDelete": {"/cgi-bin/tag/delete?access_token=%s&tagid=%v", "GET"}, | ||
"TagGetUser": {"/cgi-bin/tag/get?access_token=%s&tagid=%v", "GET"}, | ||
"TagAddUser": {"/cgi-bin/tag/addtagusers?access_token=%s", "POST"}, | ||
"TagDeleteUser": {"/cgi-bin/tag/deltagusers?access_token=%s", "POST"}, | ||
"TagGetList": {"/cgi-bin/tag/list?access_token=%s", "GET"}, | ||
|
||
"BatchJobGetResult": {"/cgi-bin/batch/getresult?access_token=%s", "GET"}, | ||
|
||
"BatchInvite": {"/cgi-bin/batch/invite?access_token=%s", "POST"}, | ||
|
||
"AgentGet": {"/cgi-bin/agent/get?access_token=%s&agentid=%v", "GET"}, | ||
"AgentSet": {"/cgi-bin/agent/set?access_token=%s", "POST"}, | ||
"AgentGetList": {"/cgi-bin/agent/list?access_token=%s", "GET"}, | ||
|
||
"MenuCreaet": {"/cgi-bin/menu/create?access_token=%s", "POST"}, // TODO | ||
"MenuGet": {"/cgi-bin/menu/get?access_token=%s", "GET"}, | ||
"MenuDelete": {"/cgi-bin/menu/delete?access_token=%s", "GET"}, | ||
|
||
"MessageSend": {"/cgi-bin/message/send?access_token=%s", "POST"}, | ||
|
||
"MediaGet": {"/cgi-bin/media/get?access_token=%s", "GET"}, | ||
|
||
"GetUserInfoByCode": {"/cgi-bin/user/getuserinfo?access_token=%s&code=%s", "GET"}, | ||
"GetUserDetail": {"/cgi-bin/user/getuserdetail?access_token=%s", "POST"}, | ||
|
||
"GetTicket": {"/cgi-bin/ticket/get?access_token=%s", "GET"}, | ||
"GetJSAPITicket": {"/cgi-bin/get_jsapi_ticket?access_token=%s", "GET"}, | ||
|
||
"GetCheckinOption": {"/cgi-bin/checkin/getcheckinoption?access_token=%s", "POST"}, | ||
"GetCheckinData": {"/cgi-bin/checkin/getcheckindata?access_token=%s", "POST"}, | ||
"GetApprovalData": {"/cgi-bin/corp/getapprovaldata?access_token=%s", "POST"}, | ||
|
||
"GetInvoiceInfo": {"/cgi-bin/card/invoice/reimburse/getinvoiceinfo?access_token=%s", "POST"}, | ||
"UpdateInvoiceStatus": {"/cgi-bin/card/invoice/reimburse/updateinvoicestatus?access_token=%s", "POST"}, | ||
"BatchUpdateInvoiceStatus": {"/cgi-bin/card/invoice/reimburse/updatestatusbatch?access_token=%s", "POST"}, | ||
"BatchGetInvoiceInfo": {"/cgi-bin/card/invoice/reimburse/getinvoiceinfobatch?access_token=%s", "POST"}, | ||
} | ||
|
||
// NewWorkAPI 创建新的企业微信应用接口 | ||
func NewWorkAPI(corpid, appsecret string, appid int) *WorkAPI { | ||
if corpid == "" || appsecret == "" { | ||
log.Fatal("CorpID or AppSecret is null, please check the config file.") | ||
} | ||
//return &WorkAPI{CorpID: corpid, AppSecret: appsecret, AppID: appid, TokenCache: cache.New(7100, 5*time.Second)} | ||
return &WorkAPI{CorpID: corpid, AppSecret: appsecret, AppID: appid, TokenCache: cache.New(7100, 5*time.Second)} | ||
} | ||
|
||
// GetAccessToken 企业微信获取或更新访问令牌 AccessToken 接口 | ||
func (wx *WorkAPI) GetAccessToken() { | ||
for { | ||
url := BaseURL + fmt.Sprintf(WorkAPIType["GetAccessToken"][0], wx.CorpID, wx.AppSecret) | ||
result, err := HTTPRequest(url, WorkAPIType["GetAccessToken"][1], nil) | ||
if err != nil { | ||
log.Printf("Get access token return error: %v", err) | ||
return | ||
} | ||
|
||
//res, err := ioutil.ReadAll(result) | ||
newAccess := accessToken{} | ||
err = jsoniter.Unmarshal(result, &newAccess) | ||
if err != nil { | ||
log.Printf("Get access token parse JSON error: %s", err) | ||
return | ||
} | ||
|
||
if newAccess.ExpiresIn == 0 || newAccess.AccessToken == "" { | ||
log.Printf("Get access token error code: %v, error message: %s", newAccess.ErrCode, newAccess.ErrMsg) | ||
time.Sleep(5 * time.Minute) | ||
} | ||
|
||
wx.TokenCache.Set("token", newAccess, time.Duration(newAccess.ExpiresIn)*time.Second) | ||
log.Printf("Access token update sucessful: %s, expired time: %v", newAccess.AccessToken, newAccess.ExpiresIn) | ||
time.Sleep(time.Duration(newAccess.ExpiresIn-100) * time.Second) | ||
} | ||
} | ||
|
||
// GetTokenString 获取企业微信接口调用令牌 | ||
func (wx *WorkAPI) GetTokenString() (string, error) { | ||
|
||
token, found := wx.TokenCache.Get("token") | ||
if found { | ||
accessToken, ok := token.(accessToken) | ||
if ok { | ||
return accessToken.AccessToken, nil | ||
} | ||
return "", errors.New("Parse Token string failed") | ||
} | ||
return "", errors.New("Get Token string failed") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package workapi | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
// GetUserInfoByCode 通过企业微信后台返回的code一次性获取用户信息 | ||
func (wx *WorkAPI) GetUserInfoByCode(code string) ([]byte, error) { | ||
token, err := wx.GetTokenString() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
url := BaseURL + fmt.Sprintf(WorkAPIType["GetUserInfoByCode"][0], token, code) | ||
|
||
body, err := HTTPRequest(url, WorkAPIType["GetUserInfoByCode"][1], nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return body, nil | ||
} | ||
|
||
// GetUserDetail 通过企业微信后台返回的user_ticket获取用户详细信息 | ||
func (wx *WorkAPI) GetUserDetail(userTicket string) ([]byte, error) { | ||
token, err := wx.GetTokenString() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
url := BaseURL + fmt.Sprintf(WorkAPIType["GetUserDetail"][0], token) | ||
|
||
d := map[string]interface{}{"user_ticket": userTicket} | ||
|
||
data, err := DataToReader(d) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
body, err := HTTPRequest(url, WorkAPIType["GetUserDetail"][1], data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return body, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package workapi | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
// CreateDepartment 创建企业微信部门信息 | ||
func (wx *WorkAPI) CreateDepartment(d Department) ([]byte, error) { | ||
token, err := wx.GetTokenString() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
url := BaseURL + fmt.Sprintf(WorkAPIType["DepartmentCreate"][0], token) | ||
|
||
data, err := DataToReader(d) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
body, err := HTTPRequest(url, WorkAPIType["DepartmentCreate"][1], data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return body, nil | ||
} | ||
|
||
// UpdateDepartment 更新企业微信部门信息 | ||
func (wx *WorkAPI) UpdateDepartment(d Department) ([]byte, error) { | ||
token, err := wx.GetTokenString() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
url := BaseURL + fmt.Sprintf(WorkAPIType["DepartmentUpdate"][0], token) | ||
|
||
data, err := DataToReader(d) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
body, err := HTTPRequest(url, WorkAPIType["DepartmentUpdate"][1], data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return body, nil | ||
} | ||
|
||
// DeleteDepartment 删除企业微信部门 | ||
func (wx *WorkAPI) DeleteDepartment(id int) ([]byte, error) { | ||
token, err := wx.GetTokenString() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
url := BaseURL + fmt.Sprintf(WorkAPIType["DepartmentList"][0], token, id) | ||
|
||
body, err := HTTPRequest(url, WorkAPIType["DepartmentList"][1], nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return body, nil | ||
} | ||
|
||
// GetDepartmentList 获取企业微信部门列表 | ||
func (wx *WorkAPI) GetDepartmentList(id int) ([]byte, error) { | ||
token, err := wx.GetTokenString() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
url := BaseURL + fmt.Sprintf(WorkAPIType["DepartmentList"][0], token) | ||
if id != 0 { | ||
url += fmt.Sprintf("&id=%v", id) | ||
} | ||
|
||
body, err := HTTPRequest(url, WorkAPIType["DepartmentList"][1], nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return body, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package workapi | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"net/http" | ||
) | ||
|
||
// HTTPRequest http请求客户端 | ||
func HTTPRequest(url string, method string, body io.Reader) ([]byte, error) { | ||
|
||
client := &http.Client{} | ||
|
||
request, err := http.NewRequest(method, url, body) | ||
if err != nil { | ||
return nil, err | ||
|
||
} | ||
|
||
if method == "POST" { | ||
request.Header.Set("Accept", "application/json") | ||
request.Header.Set("Content-Type", "application/json; charset=UTF-8") | ||
} | ||
|
||
//处理返回结果 | ||
response, err := client.Do(request) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
defer response.Body.Close() | ||
|
||
buf, err := ioutil.ReadAll(response.Body) | ||
|
||
if response.StatusCode == http.StatusOK { | ||
return buf, nil | ||
} | ||
|
||
return nil, errors.New(fmt.Sprint("StatusCode=", response.StatusCode, " msg=", string(buf))) | ||
|
||
} | ||
|
||
// PostRequest POST 方式调用 HTTP 请求 | ||
func PostRequest(url string, body io.Reader) ([]byte, error) { | ||
return HTTPRequest(url, "POST", body) | ||
} | ||
|
||
// GetRequest GET 方式调用 HTTP 请求 | ||
func GetRequest(url string) ([]byte, error) { | ||
return HTTPRequest(url, "GET", nil) | ||
} |
Oops, something went wrong.