Пример #1
0
    def _fetch_access_token(self, url, data):
        """ The real fetch access token """
        logger.info("Fetching component access token")
        res = self._http.post(url=url, data=data)
        try:
            res.raise_for_status()
        except requests.RequestException as reqe:
            raise WeChatClientException(
                errcode=None,
                errmsg=None,
                client=self,
                request=reqe.request,
                response=reqe.response,
            )
        result = res.json()
        if "errcode" in result and result["errcode"] != 0:
            raise WeChatClientException(
                result["errcode"],
                result["errmsg"],
                client=self,
                request=res.request,
                response=res,
            )

        expires_in = 7200
        if "expires_in" in result:
            expires_in = result["expires_in"]
        self.session.set("component_access_token",
                         result["component_access_token"], expires_in)
        self.expires_at = int(time.time()) + expires_in
        return result
Пример #2
0
    def _fetch_access_token(self, url, params):
        """
        替代 requests 版本 _fetch_access_token
        """
        http_client = AsyncHTTPClient()
        params = urlencode(dict((k, to_binary(v)) for k, v in params.items()))
        _url = '{0}?{1}'.format(url, params)

        req = HTTPRequest(url=_url, method="GET", request_timeout=self.timeout)
        res = yield http_client.fetch(req)
        if res.error is not None:
            raise WeChatClientException(errcode=None,
                                        errmsg=None,
                                        client=self,
                                        request=req,
                                        response=res)

        result = self._decode_result(res)

        if 'errcode' in result and result['errcode'] != 0:
            raise WeChatClientException(result['errcode'],
                                        result['errmsg'],
                                        client=self,
                                        request=res.request,
                                        response=res)

        expires_in = 7200
        if 'expires_in' in result:
            expires_in = result['expires_in']
        self.session.set(self.access_token_key, result['access_token'],
                         expires_in)
        self.expires_at = int(time.time()) + expires_in
        raise Return(result)
Пример #3
0
    def _fetch_access_token(self, url, params):
        """ The real fetch access token """
        res = requests.get(url=url, params=params)
        try:
            res.raise_for_status()
        except requests.RequestException as reqe:
            raise WeChatClientException(errcode=None,
                                        errmsg=None,
                                        client=self,
                                        request=reqe.request,
                                        response=reqe.response)
        result = res.json()
        if 'errcode' in result and result['errcode'] != 0:
            raise WeChatClientException(result['errcode'],
                                        result['errmsg'],
                                        client=self,
                                        request=res.request,
                                        response=res)

        expires_in = 7200
        if 'expires_in' in result:
            expires_in = result['expires_in']
        self.session.set('access_token', result['access_token'], expires_in)
        self.expires_at = int(time.time()) + expires_in
        return result
Пример #4
0
    def _request(self, method, url_or_endpoint, **kwargs):
        if not url_or_endpoint.startswith(('http://', 'https://')):
            api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL)
            url = '{base}{endpoint}'.format(base=api_base_url,
                                            endpoint=url_or_endpoint)
        else:
            url = url_or_endpoint

        if 'params' not in kwargs:
            kwargs['params'] = {}
        if isinstance(kwargs['params'], dict) and \
                'component_access_token' not in kwargs['params']:
            kwargs['params']['component_access_token'] = self.access_token
        if isinstance(kwargs['data'], dict):
            kwargs['data'] = json.dumps(kwargs['data'])

        res = requests.request(method=method, url=url, **kwargs)
        try:
            res.raise_for_status()
        except requests.RequestException as reqe:
            raise WeChatClientException(errcode=None,
                                        errmsg=None,
                                        client=self,
                                        request=reqe.request,
                                        response=reqe.response)

        return self._handle_result(res, method, url, **kwargs)
Пример #5
0
    def _handle_result(self, res, method=None, url=None, **kwargs):
        result = json.loads(res.content.decode('utf-8', 'ignore'),
                            strict=False)
        if 'errcode' in result:
            result['errcode'] = int(result['errcode'])

        if 'errcode' in result and result['errcode'] != 0:
            errcode = result['errcode']
            errmsg = result['errmsg']
            if errcode == 42001:
                logger.info(
                    'Component access token expired, fetch a new one and retry request'
                )
                self.fetch_access_token()
                kwargs['params']['component_access_token'] = self.session.get(
                    'component_access_token')
                return self._request(method=method,
                                     url_or_endpoint=url,
                                     **kwargs)
            elif errcode == 45009:
                # api freq out of limit
                raise APILimitedException(errcode,
                                          errmsg,
                                          client=self,
                                          request=res.request,
                                          response=res)
            else:
                raise WeChatClientException(errcode,
                                            errmsg,
                                            client=self,
                                            request=res.request,
                                            response=res)

        return result
Пример #6
0
    def _request(self, method, url_or_endpoint, **kwargs):
        if not url_or_endpoint.startswith(('http://', 'https://')):
            api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL)
            url = '{base}{endpoint}'.format(base=api_base_url,
                                            endpoint=url_or_endpoint)
        else:
            url = url_or_endpoint

        if 'params' not in kwargs:
            kwargs['params'] = {}
        if isinstance(kwargs['params'], dict) and \
                'access_token' not in kwargs['params']:
            kwargs['params']['access_token'] = self.access_token
        if isinstance(kwargs.get('data', ''), dict):
            body = json.dumps(kwargs['data'], ensure_ascii=False)
            body = body.encode('utf-8')
            kwargs['data'] = body

        kwargs['timeout'] = kwargs.get('timeout', self.timeout)
        result_processor = kwargs.pop('result_processor', None)
        res = self._http.request(method=method, url=url, **kwargs)
        try:
            res.raise_for_status()
        except requests.RequestException as reqe:
            raise WeChatClientException(errcode=None,
                                        errmsg=None,
                                        client=self,
                                        request=reqe.request,
                                        response=reqe.response)

        return self._handle_result(res, method, url, result_processor,
                                   **kwargs)
Пример #7
0
    def _handle_result(self, res, method=None, url=None, **kwargs):
        result = json.loads(res.content.decode("utf-8", "ignore"), strict=False)
        if "errcode" in result:
            result["errcode"] = int(result["errcode"])

        if "errcode" in result and result["errcode"] != 0:
            errcode = result["errcode"]
            errmsg = result.get("errmsg", errcode)
            if self.auto_retry and errcode in (
                WeChatErrorCode.INVALID_CREDENTIAL.value,
                WeChatErrorCode.INVALID_ACCESS_TOKEN.value,
                WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value,
            ):
                logger.info("Component access token expired, fetch a new one and retry request")
                self.fetch_access_token()
                kwargs["params"]["component_access_token"] = self.session.get(
                    "{}_component_access_token".format(self.component_appid)
                )
                return self._request(method=method, url_or_endpoint=url, **kwargs)
            elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value:
                # api freq out of limit
                raise APILimitedException(errcode, errmsg, client=self, request=res.request, response=res)
            else:
                raise WeChatClientException(errcode, errmsg, client=self, request=res.request, response=res)
        return result
Пример #8
0
    def _request(self, method, url_or_endpoint, **kwargs):
        if not url_or_endpoint.startswith(('http://', 'https://')):
            api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL)
            url = '{base}{endpoint}'.format(base=api_base_url,
                                            endpoint=url_or_endpoint)
        else:
            url = url_or_endpoint

        # 群发消息上传视频接口地址 HTTPS 证书错误,暂时忽略证书验证
        if url.startswith('https://file.api.weixin.qq.com'):
            kwargs['verify'] = False

        if 'params' not in kwargs:
            kwargs['params'] = {}
        if isinstance(kwargs['params'], dict) and \
                'access_token' not in kwargs['params']:
            kwargs['params']['access_token'] = self.access_token
        if isinstance(kwargs.get('data', ''), dict):
            body = json.dumps(kwargs['data'], ensure_ascii=False)
            body = body.encode('utf-8')
            kwargs['data'] = body

        res = requests.request(method=method, url=url, **kwargs)
        try:
            res.raise_for_status()
        except requests.RequestException as reqe:
            raise WeChatClientException(errcode=None,
                                        errmsg=None,
                                        client=self,
                                        request=reqe.request,
                                        response=reqe.response)

        return self._handle_result(res, method, url, **kwargs)
Пример #9
0
    def _request(self, method, url_or_endpoint, **kwargs):
        if not url_or_endpoint.startswith(("http://", "https://")):
            api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL)
            url = f"{api_base_url}{url_or_endpoint}"
        else:
            url = url_or_endpoint

        if "params" not in kwargs:
            kwargs["params"] = {}
        if isinstance(kwargs["params"],
                      dict) and "suite_access_token" not in kwargs["params"]:
            kwargs["params"]["suite_access_token"] = self.access_token
        if isinstance(kwargs.get("data", ""), dict):
            body = json.dumps(kwargs["data"], ensure_ascii=False)
            body = body.encode("utf-8")
            kwargs["data"] = body

        kwargs["timeout"] = kwargs.get("timeout", self.timeout)
        result_processor = kwargs.pop("result_processor", None)
        res = self._http.request(method=method, url=url, **kwargs)
        try:
            res.raise_for_status()
        except requests.RequestException as reqe:
            raise WeChatClientException(
                errcode=None,
                errmsg=None,
                client=self,
                request=reqe.request,
                response=reqe.response,
            )

        return self._handle_result(res, method, url, result_processor,
                                   **kwargs)
Пример #10
0
    def _request(self, method, url_or_endpoint, **kwargs):
        if not url_or_endpoint.startswith(("http://", "https://")):
            api_base_url = kwargs.pop("api_base_url", self.API_BASE_URL)
            url = f"{api_base_url}{url_or_endpoint}"
        else:
            url = url_or_endpoint

        if "params" not in kwargs:
            kwargs["params"] = {}
        if isinstance(
                kwargs["params"],
                dict) and "component_access_token" not in kwargs["params"]:
            kwargs["params"]["component_access_token"] = self.access_token
        if isinstance(kwargs["data"], dict):
            kwargs["data"] = json.dumps(kwargs["data"])

        res = self._http.request(method=method, url=url, **kwargs)
        try:
            res.raise_for_status()
        except requests.RequestException as reqe:
            raise WeChatClientException(
                errcode=None,
                errmsg=None,
                client=self,
                request=reqe.request,
                response=reqe.response,
            )

        return self._handle_result(res, method, url, **kwargs)
Пример #11
0
    def _handle_result(self, res, method=None, url=None, **kwargs):
        res.encoding = 'utf-8'
        result = res.json()
        if 'base_resp' in result:
            # Different response in device APIs. F**k tencent!
            result = result['base_resp']
        if 'errcode' in result:
            result['errcode'] = int(result['errcode'])

        if 'errcode' in result and result['errcode'] != 0:
            errcode = result['errcode']
            errmsg = result['errmsg']
            if errcode == 42001:
                # access_token expired, fetch a new one and retry request
                self.fetch_access_token()
                kwargs['params']['access_token'] = self.session.get(
                    'access_token')
                return self._request(method=method,
                                     url_or_endpoint=url,
                                     **kwargs)
            elif errcode == 45009:
                # api freq out of limit
                raise APILimitedException(errcode,
                                          errmsg,
                                          client=self,
                                          request=res.request,
                                          response=res)
            else:
                raise WeChatClientException(errcode,
                                            errmsg,
                                            client=self,
                                            request=res.request,
                                            response=res)

        return result
Пример #12
0
    def auth(self, code, scope=None):
        """用code进行微信授权
        :rtype: (wechat_django.models.WeChatUser, dict)
        :raises: wechatpy.exceptions.WeChatClientException
        :raises: wechatpy.exceptions.WeChatOAuthException
        """
        if not self.abilities.api:
            raise WeChatClientException(WeChatErrorCode.INVALID_CREDENTIAL)

        if self.type == WeChatApp.Type.SERVICEAPP:
            if not self.abilities.oauth:
                raise WeChatClientException(WeChatErrorCode.UNAUTHORIZED_API)
            return self._auth_service(code, scope)
        elif self.type == WeChatApp.Type.MINIPROGRAM:
            return self._auth_miniprogram(code)
        else:
            raise WeChatClientException(WeChatErrorCode.UNAUTHORIZED_API)
Пример #13
0
    def _handle_result(self, res, method=None, url=None,
                       result_processor=None, **kwargs):
        if not isinstance(res, dict):
            # Dirty hack around asyncio based AsyncWeChatClient
            result = self._decode_result(res)
        else:
            result = res

        if not isinstance(result, dict):
            return result

        if 'base_resp' in result:
            # Different response in device APIs. F**k tencent!
            result.update(result.pop('base_resp'))
        if 'errcode' in result:
            result['errcode'] = int(result['errcode'])

        if 'errcode' in result and result['errcode'] != 0:
            errcode = result['errcode']
            errmsg = result.get('errmsg', errcode)
            if self.auto_retry and errcode in (
                    WeChatErrorCode.INVALID_CREDENTIAL.value,
                    WeChatErrorCode.INVALID_ACCESS_TOKEN.value,
                    WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value):
                logger.info('Access token expired, fetch a new one and retry request')
                self.fetch_access_token()
                access_token, expires_at = self.session.get(self.access_token_key)
                kwargs['params']['access_token'] = access_token
                return self._request(
                    method=method,
                    url_or_endpoint=url,
                    result_processor=result_processor,
                    **kwargs
                )
            elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value:
                # api freq out of limit
                raise APILimitedException(
                    errcode,
                    errmsg,
                    client=self,
                    request=res.request,
                    response=res
                )
            else:
                raise WeChatClientException(
                    errcode,
                    errmsg,
                    client=self,
                    request=res.request,
                    response=res
                )

        return result if not result_processor else result_processor(result)
Пример #14
0
    def _request(self, method, url_or_endpoint, **kwargs):
        http_client = AsyncHTTPClient()
        if not url_or_endpoint.startswith(('http://', 'https://')):
            api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL)
            url = '{base}{endpoint}'.format(base=api_base_url,
                                            endpoint=url_or_endpoint)
        else:
            url = url_or_endpoint

        headers = {}
        params = kwargs.pop('params', {})
        if 'access_token' not in params:
            params['access_token'] = self.access_token

        params = urlencode(dict((k, to_binary(v)) for k, v in params.items()))
        url = '{0}?{1}'.format(url, params)

        data = kwargs.get('data')
        files = kwargs.get('files')
        if files:
            from requests.models import RequestEncodingMixin
            from requests.utils import super_len

            body, content_type = RequestEncodingMixin._encode_files(
                files, data)
            headers['Content-Type'] = content_type
            headers['Content-Length'] = super_len(body)
        else:
            if isinstance(data, dict):
                body = json.dumps(data, ensure_ascii=False)
                body = body.encode('utf-8')
            else:
                body = data

        result_processor = kwargs.pop('result_processor', None)
        timeout = kwargs.get('timeout', self.timeout)
        req = HTTPRequest(url=url,
                          method=method.upper(),
                          headers=headers,
                          body=body,
                          request_timeout=timeout)
        res = yield http_client.fetch(req)
        if res.error is not None:
            raise WeChatClientException(errcode=None,
                                        errmsg=None,
                                        client=self,
                                        request=req,
                                        response=res)

        result = self._handle_result(res, method, url, result_processor,
                                     **kwargs)
        raise Return(result)
Пример #15
0
    def _fetch_access_token(self, url, params):
        """ The real fetch access token """
        res = requests.get(url=url, params=params)
        result = res.json()
        if 'errcode' in result and result['errcode'] != 0:
            raise WeChatClientException(result['errcode'], result['errmsg'])

        self._access_token = result['access_token']
        expires_in = 7200
        if 'expires_in' in result:
            expires_in = result['expires_in']
        self.expires_at = int(time.time()) + expires_in
        return result
Пример #16
0
    def _handle_result(self, res, method=None, url=None,
                       result_processor=None, **kwargs):
        if not isinstance(res, dict):
            # Dirty hack around asyncio based AsyncWeChatClient
            result = self._decode_result(res)
        else:
            result = res

        if not isinstance(result, dict):
            return result

        if 'base_resp' in result:
            # Different response in device APIs. F**k tencent!
            result = result['base_resp']
        if 'errcode' in result:
            result['errcode'] = int(result['errcode'])

        if 'errcode' in result and result['errcode'] != 0:
            errcode = result['errcode']
            errmsg = result['errmsg']
            if errcode in (40001, 40014, 42001):
                # access_token expired, fetch a new one and retry request
                self.fetch_access_token()
                access_token = self.session.get(self.access_token_key)
                kwargs['params']['access_token'] = access_token
                return self._request(
                    method=method,
                    url_or_endpoint=url,
                    result_processor=result_processor,
                    **kwargs
                )
            elif errcode == 45009:
                # api freq out of limit
                raise APILimitedException(
                    errcode,
                    errmsg,
                    client=self,
                    request=res.request,
                    response=res
                )
            else:
                raise WeChatClientException(
                    errcode,
                    errmsg,
                    client=self,
                    request=res.request,
                    response=res
                )

        return result if not result_processor else result_processor(result)
Пример #17
0
    def _request(self, method, url_or_endpoint, **kwargs):
        http_client = AsyncHTTPClient()
        if not url_or_endpoint.startswith(('http://', 'https://')):
            api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL)
            url = '{base}{endpoint}'.format(
                base=api_base_url,
                endpoint=url_or_endpoint
            )
        else:
            url = url_or_endpoint

        headers = {}
        params = kwargs.pop('params', {})

        params = urlencode(dict((k, to_binary(v)) for k, v in params.items()))
        url = '{0}?{1}'.format(url, params)
        
        data = kwargs.get('data')
        if isinstance(data, dict):
            data = optionaldict(data)
            if 'mchid' not in data:
                # F**k Tencent
                data.setdefault('mch_id', self.mch_id)
            data.setdefault('sub_mch_id', self.sub_mch_id)
            data.setdefault('nonce_str', random_string(32))
            sign = calculate_signature(data, self.api_key)
            body = dict_to_xml(data, sign)
            body = body.encode('utf-8')
        else:
            body = data

        req = HTTPRequest(
            url=url,
            method=method.upper(),
            headers=headers,
            body=body
        )
        res = yield http_client.fetch(req)
        if res.error is not None:
            raise WeChatClientException(
                errcode=None,
                errmsg=None,
                client=self,
                request=req,
                response=res
            )

        result = self._handle_result(res)
        raise Return(result)
Пример #18
0
    def _handle_result(self, res, method=None, url=None, **kwargs):
        result = json.loads(res.content.decode('utf-8', 'ignore'), strict=False)
        if 'errcode' in result:
            result['errcode'] = int(result['errcode'])

        if 'errcode' in result and result['errcode'] != 0:
            errcode = result['errcode']
            errmsg = result.get('errmsg', errcode)
            if self.auto_retry and errcode in (
                    WeChatErrorCode.INVALID_CREDENTIAL.value,
                    WeChatErrorCode.INVALID_ACCESS_TOKEN.value,
                    WeChatErrorCode.EXPIRED_ACCESS_TOKEN.value):
                logger.info('Component access token expired, fetch a new one and retry request')
                self.fetch_access_token()
                kwargs['params']['component_access_token'] = self.session.get(
                    'component_access_token'
                )
                return self._request(
                    method=method,
                    url_or_endpoint=url,
                    **kwargs
                )
            elif errcode == WeChatErrorCode.OUT_OF_API_FREQ_LIMIT.value:
                # api freq out of limit
                raise APILimitedException(
                    errcode,
                    errmsg,
                    client=self,
                    request=res.request,
                    response=res
                )
            else:
                raise WeChatClientException(
                    errcode,
                    errmsg,
                    client=self,
                    request=res.request,
                    response=res
                )
        return result
Пример #19
0
    def _handle_result(self, res, method=None, url=None, **kwargs):
        res.encoding = 'utf-8'
        try:
            result = res.json()
        except (TypeError, ValueError):
            # Return origin response object if we can not decode it as JSON
            return res

        if 'base_resp' in result:
            # Different response in device APIs. F**k tencent!
            result = result['base_resp']
        if 'errcode' in result:
            result['errcode'] = int(result['errcode'])

        if 'errcode' in result and result['errcode'] != 0:
            errcode = result['errcode']
            errmsg = result['errmsg']
            if errcode in (40001, 40014, 42001):
                # access_token expired, fetch a new one and retry request
                self.fetch_access_token()
                access_token = self.session.get(self.access_token_key)
                kwargs['params']['access_token'] = access_token
                return self._request(method=method,
                                     url_or_endpoint=url,
                                     **kwargs)
            elif errcode == 45009:
                # api freq out of limit
                raise APILimitedException(errcode,
                                          errmsg,
                                          client=self,
                                          request=res.request,
                                          response=res)
            else:
                raise WeChatClientException(errcode,
                                            errmsg,
                                            client=self,
                                            request=res.request,
                                            response=res)

        return result