diff --git a/platformapi/dingdingapi/dingdingapi.go b/platformapi/dingdingapi/dingdingapi.go new file mode 100644 index 00000000..1a1db962 --- /dev/null +++ b/platformapi/dingdingapi/dingdingapi.go @@ -0,0 +1,129 @@ +package dingdingapi + +import ( + "net/http" + "strings" + "sync" + + "git.rosy.net.cn/baseapi/platformapi" + "git.rosy.net.cn/baseapi/utils" +) + +const ( + prodURL = "https://oapi.dingtalk.com" +) + +const ( + getTokenAction = "gettoken" + snsGetTokenAction = "sns/gettoken" +) + +const ( + ResponseCodeSuccess = 0 +) + +type API struct { + token string + appID string + secret string + client *http.Client + config *platformapi.APIConfig + locker sync.RWMutex +} + +func New(appID, secret string, config ...*platformapi.APIConfig) *API { + curConfig := platformapi.DefAPIConfig + if len(config) > 0 { + curConfig = *config[0] + } + return &API{ + appID: appID, + secret: secret, + client: &http.Client{Timeout: curConfig.ClientTimeout}, + config: &curConfig, + } +} + +func (a *API) GetAppID() string { + return a.appID +} + +func (a *API) GetSecret() string { + return a.secret +} + +func isSNSAction(action string) bool { + return strings.Index(action, "sns/") == 0 +} + +func (a *API) SetToken(newToken string) bool { + curToken := a.GetToken() + if curToken != newToken { + a.locker.Lock() + defer a.locker.Unlock() + a.token = newToken + return true + } + return false +} + +func (a *API) GetToken() string { + a.locker.RLock() + defer a.locker.RUnlock() + return a.token +} + +func (a *API) RetrieveToken() (token string, err error) { + result, err := a.AccessAPI(getTokenAction, nil, "") + if err != nil { + return "", err + } + token = utils.Interface2String(result["access_token"]) + a.SetToken(token) + return token, nil +} + +func (a *API) AccessAPI(action string, params map[string]interface{}, body string) (retVal map[string]interface{}, err error) { + params2 := make(map[string]interface{}) + for k, v := range params { + params2[k] = v + } + if action == getTokenAction { + params2["appkey"] = a.GetAppID() + params2["appsecret"] = a.GetSecret() + } else if action == snsGetTokenAction { + params2["appid"] = a.GetAppID() + params2["appsecret"] = a.GetSecret() + } else if !isSNSAction(action) { + accessToken := a.GetToken() + if accessToken == "" { + panic("token is empty!") + } + params2["access_token"] = accessToken + } + + fullURL := utils.GenerateGetURL(prodURL, action, params2) + // baseapi.SugarLogger.Debug(fullURL) + + err = platformapi.AccessPlatformAPIWithRetry(a.client, + func() *http.Request { + var request *http.Request + if body == "" { + request, _ = http.NewRequest(http.MethodGet, fullURL, nil) + } else { + request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(body)) + } + return request + }, + a.config, + func(jsonResult1 map[string]interface{}) (result string, err error) { + errCode := int(utils.MustInterface2Int64(jsonResult1["errcode"])) + if errCode == ResponseCodeSuccess { + retVal = jsonResult1 + return platformapi.ErrLevelSuccess, nil + } + newErr := utils.NewErrorIntCode(utils.Interface2String(jsonResult1["errmsg"]), errCode) + return platformapi.ErrLevelCodeIsNotOK, newErr + }) + return retVal, err +} diff --git a/platformapi/dingdingapi/dingdingapi_test.go b/platformapi/dingdingapi/dingdingapi_test.go new file mode 100644 index 00000000..1221ed9c --- /dev/null +++ b/platformapi/dingdingapi/dingdingapi_test.go @@ -0,0 +1,30 @@ +package dingdingapi + +import ( + "testing" + + "git.rosy.net.cn/baseapi" + + "go.uber.org/zap" +) + +var ( + api *API + sugarLogger *zap.SugaredLogger +) + +func init() { + logger, _ := zap.NewDevelopment() + sugarLogger = logger.Sugar() + baseapi.Init(sugarLogger) + + api = New("ding7iu9cptairtcls0c", "LWrZAFeqUfuVv7n_tc8vPpCAx6PT4CwManx2XCVhJOqGsx2L5XCDuX1sAN_JtvsI") +} + +func TestRetrieveToken(t *testing.T) { + result, err := api.RetrieveToken() + if err != nil { + t.Fatal(err.Error()) + } + sugarLogger.Debug(result) +} diff --git a/platformapi/dingdingapi/staff.go b/platformapi/dingdingapi/staff.go new file mode 100644 index 00000000..fa76d4e4 --- /dev/null +++ b/platformapi/dingdingapi/staff.go @@ -0,0 +1,29 @@ +package dingdingapi + +import "git.rosy.net.cn/baseapi/utils" + +type UserID struct { + UserID string `json:"userid"` + IsSys bool `json:"is_sys"` + DeviceID string `json:"deviceId"` +} + +func (a *API) GetUserID(code string) (userID *UserID, err error) { + result, err := a.AccessAPI("user/getuserinfo", utils.Params2Map("code", code), "") + if err != nil { + return nil, err + } + return &UserID{ + UserID: utils.Interface2String(result["userid"]), + IsSys: result["deviceId"].(bool), + DeviceID: utils.Interface2String(result["deviceId"]), + }, nil +} + +func (a *API) GetUserDetail(userID string) (userDetail map[string]interface{}, err error) { + result, err := a.AccessAPI("user/get", utils.Params2Map("userid", userID), "") + if err != nil { + return nil, err + } + return result, nil +} diff --git a/platformapi/weixinapi/cgibin.go b/platformapi/weixinapi/cgibin.go index b360ef21..ff58a4d2 100644 --- a/platformapi/weixinapi/cgibin.go +++ b/platformapi/weixinapi/cgibin.go @@ -28,16 +28,10 @@ func (a *API) CBRetrieveToken() (tokenInfo *TokenInfo, err error) { AccessToken: utils.Interface2String(result["access_token"]), ExpiresIn: int(utils.MustInterface2Int64(result["expires_in"])), } + a.CBSetToken(tokenInfo.AccessToken) return tokenInfo, nil } -func (a *API) CBRefreshToken() (tokenInfo *TokenInfo, err error) { - if tokenInfo, err = a.CBRetrieveToken(); err == nil { - a.CBSetToken(tokenInfo.AccessToken) - } - return tokenInfo, err -} - func (a *API) CBMessageTemplateSend(userOpenID, templateID, downloadURL string, miniProgram, data interface{}) (err error) { bodyJson := map[string]interface{}{ "touser": userOpenID, diff --git a/platformapi/weixinapi/cgibin_test.go b/platformapi/weixinapi/cgibin_test.go index 33aa8b7a..d38c3b45 100644 --- a/platformapi/weixinapi/cgibin_test.go +++ b/platformapi/weixinapi/cgibin_test.go @@ -2,8 +2,8 @@ package weixinapi import "testing" -func TestRefreshToken(t *testing.T) { - result, err := weixinapi.CBRefreshToken() +func TestCBRetrieveToken(t *testing.T) { + result, err := weixinapi.CBRetrieveToken() if err != nil || result.ExpiresIn != 7200 { t.Fatal(err.Error()) }