weixin_authorize_905 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +19 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +11 -0
  6. data/Gemfile +5 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +72 -0
  9. data/Rakefile +1 -0
  10. data/lib/weixin_authorize.rb +97 -0
  11. data/lib/weixin_authorize/api.rb +3 -0
  12. data/lib/weixin_authorize/api/custom.rb +176 -0
  13. data/lib/weixin_authorize/api/data_cube.rb +8 -0
  14. data/lib/weixin_authorize/api/groups.rb +60 -0
  15. data/lib/weixin_authorize/api/mass.rb +80 -0
  16. data/lib/weixin_authorize/api/media.rb +149 -0
  17. data/lib/weixin_authorize/api/menu.rb +36 -0
  18. data/lib/weixin_authorize/api/oauth.rb +50 -0
  19. data/lib/weixin_authorize/api/qrcode.rb +62 -0
  20. data/lib/weixin_authorize/api/template.rb +34 -0
  21. data/lib/weixin_authorize/api/user.rb +69 -0
  22. data/lib/weixin_authorize/carrierwave/weixin_uploader.rb +4 -0
  23. data/lib/weixin_authorize/client.rb +95 -0
  24. data/lib/weixin_authorize/config.rb +35 -0
  25. data/lib/weixin_authorize/handler.rb +3 -0
  26. data/lib/weixin_authorize/handler/exceptions.rb +5 -0
  27. data/lib/weixin_authorize/handler/global_code.rb +127 -0
  28. data/lib/weixin_authorize/handler/result_handler.rb +52 -0
  29. data/lib/weixin_authorize/js_ticket/object_store.rb +21 -0
  30. data/lib/weixin_authorize/js_ticket/redis_store.rb +41 -0
  31. data/lib/weixin_authorize/js_ticket/store.rb +40 -0
  32. data/lib/weixin_authorize/token/object_store.rb +25 -0
  33. data/lib/weixin_authorize/token/redis_store.rb +38 -0
  34. data/lib/weixin_authorize/token/store.rb +72 -0
  35. data/lib/weixin_authorize/version.rb +3 -0
  36. data/spec/1_fetch_access_token_spec.rb +43 -0
  37. data/spec/2_fetch_jsticket_spec.rb +10 -0
  38. data/spec/api/custom_spec.rb +71 -0
  39. data/spec/api/groups_spec.rb +74 -0
  40. data/spec/api/mass_spec.rb +70 -0
  41. data/spec/api/media_spec.rb +82 -0
  42. data/spec/api/medias/favicon.ico +0 -0
  43. data/spec/api/medias/ruby-logo.jpg +0 -0
  44. data/spec/api/menu_spec.rb +26 -0
  45. data/spec/api/qrcode_spec.rb +22 -0
  46. data/spec/api/template_spec.rb +40 -0
  47. data/spec/api/user_spec.rb +26 -0
  48. data/spec/spec_helper.rb +130 -0
  49. data/weixin_authorize.gemspec +48 -0
  50. metadata +301 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 33505003ed37e5e14fed39e7fd50531878c2fb97
4
+ data.tar.gz: a4b792fc8c883a0430a94f3b72167b50ebc5fc27
5
+ SHA512:
6
+ metadata.gz: c77ffe352aed9ae672df34050be27adff4ea57e26388db36ed70e44fe0adec275567827e15c7b1c76948be1110d74c70593ab4eda07b1a1e7602e097b66bf5fa
7
+ data.tar.gz: ad1c42fce64906308bf6c9455c448b3857447425372420d78f6b9b5110be343441d3b384fb70fb80c52e67998d005c96f79913d0c00fbb9dc97d51d0586d5e9f
@@ -0,0 +1,2 @@
1
+ service_name: travis-pro
2
+ repo_token: aAaaYkiZrS6MHUIbKFdM1b5EnevvVZ4MQ
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *DS_Store
19
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation --color spec --drb
2
+ --require spec_helper
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ bundler_args:
3
+ rvm:
4
+ - 2.0.0
5
+ script:
6
+ - bundle exec rspec spec
7
+ services:
8
+ - redis
9
+ addons:
10
+ code_climate:
11
+ repo_token: c91fecbbd9e414e7cc3ad7a7d99207145de0ac65a3368de09e8c19295343d399
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in weixin_authorize.gemspec
4
+ gemspec name: 'weixin_authorize_905'
5
+
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 lanrion
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,72 @@
1
+ # WeixinAuthorize
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/weixin_authorize.png)](http://badge.fury.io/rb/weixin_authorize)
4
+ [![Build Status](https://secure.travis-ci.org/lanrion/weixin_authorize.png?branch=master)](http://travis-ci.org/lanrion/weixin_authorize)
5
+ [![Code Climate](https://codeclimate.com/github/lanrion/weixin_authorize.png)](https://codeclimate.com/github/lanrion/weixin_authorize)
6
+ [![Coverage Status](https://codeclimate.com/github/lanrion/weixin_authorize/coverage.png)](https://codeclimate.com/github/lanrion/weixin_authorize)
7
+
8
+ Support using [Redis](http://redis.io) to store `access_token`
9
+
10
+ [Wiki](https://github.com/lanrion/weixin_authorize/wiki)
11
+
12
+ [Getting-Started](https://github.com/lanrion/weixin_authorize/wiki/Getting-Started)
13
+
14
+ [JS SDK](https://github.com/lanrion/weixin_authorize/wiki/js-sdk)
15
+
16
+ ## 支持自助实现API
17
+
18
+ 详情见:https://github.com/lanrion/weixin_authorize/wiki/diy-your-api
19
+
20
+ ## 已经完成API
21
+
22
+ * 客服消息
23
+ * 模板消息
24
+ * 用户分组管理
25
+ * 用户信息管理
26
+ * Oauth 2授权
27
+ * 二维码生成
28
+ * 自定义菜单
29
+ * 群发消息
30
+ * 多媒体管理
31
+ * JS SDK(ticket支持缓存)
32
+ * 更多请查看测试例子
33
+
34
+ ## V2.0开发中:
35
+ https://github.com/lanrion/weixin_authorize/milestones/v2.0-dev
36
+
37
+ 1. 重构API实现,调用方式
38
+ 2. 对token,ticket的管理,提供第三方开发灵活者自助化
39
+ 3. 尝试RestClient的弃用,选择更高效的HTTP client包
40
+ 4. 支持更多的异常处理机制
41
+
42
+ 注意:查看Wiki或者源代码时,请切换对应的版本来查看。Master处于不断更新完善分支。
43
+
44
+ ## How to test
45
+
46
+ Go to https://github.com/lanrion/weixin_authorize/issues/2, apply a weixin sandbox test account and follow this account
47
+
48
+ https://github.com/lanrion/weixin_authorize/blob/master/spec/spec_helper.rb
49
+
50
+ change your infos:
51
+
52
+ ```ruby
53
+ ENV["APPID"]="wxe371e0960de5426a"
54
+ ENV["APPSECRET"]="572b93d3d20aea242692a804243a141b"
55
+ ENV["OPENID"]="oEEoyuEasxionjR5HygmEOQGwRcw"
56
+ ```
57
+
58
+ then run `rspec .`
59
+
60
+ ## Contributing
61
+
62
+ 1. Fork it
63
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
64
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
65
+ 4. Push to the branch (`git push origin my-new-feature`)
66
+ 5. Create new Pull Request
67
+
68
+ ## 捐赠支持
69
+
70
+ 如果你觉得我的gem对你有帮助,欢迎打赏支持,:smile:
71
+
72
+ ![](https://raw.githubusercontent.com/lanrion/my_config/master/imagex/donation_me_wx.jpg)
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,97 @@
1
+ require "rest-client"
2
+ require "carrierwave"
3
+ if defined? Yajl
4
+ require 'yajl/json_gem'
5
+ else
6
+ require "json"
7
+ end
8
+ require "erb"
9
+
10
+ require "weixin_authorize/carrierwave/weixin_uploader"
11
+ require "weixin_authorize/config"
12
+ require "weixin_authorize/handler"
13
+ require "weixin_authorize/api"
14
+ require "weixin_authorize/client"
15
+
16
+ module WeixinAuthorize
17
+
18
+ # token store
19
+ module Token
20
+ autoload(:Store, "weixin_authorize/token/store")
21
+ autoload(:ObjectStore, "weixin_authorize/token/object_store")
22
+ autoload(:RedisStore, "weixin_authorize/token/redis_store")
23
+ end
24
+
25
+ module JsTicket
26
+ autoload(:Store, "weixin_authorize/js_ticket/store")
27
+ autoload(:ObjectStore, "weixin_authorize/js_ticket/object_store")
28
+ autoload(:RedisStore, "weixin_authorize/js_ticket/redis_store")
29
+ end
30
+
31
+ OK_MSG = "ok".freeze
32
+ OK_CODE = 0.freeze
33
+ GRANT_TYPE = "client_credential".freeze
34
+ # 用于标记endpoint可以直接使用url作为完整请求API
35
+ CUSTOM_ENDPOINT = "custom_endpoint".freeze
36
+
37
+ class << self
38
+
39
+ def http_get_without_token(url, url_params={}, endpoint="plain")
40
+ get_api_url = endpoint_url(endpoint, url)
41
+ load_json(resource(get_api_url).get(params: url_params))
42
+ end
43
+
44
+ def http_post_without_token(url, post_body={}, url_params={}, endpoint="plain")
45
+ post_api_url = endpoint_url(endpoint, url)
46
+ # to json if invoke "plain"
47
+ if endpoint == "plain" || endpoint == CUSTOM_ENDPOINT
48
+ post_body = JSON.dump(post_body)
49
+ end
50
+ load_json(resource(post_api_url).post(post_body, params: url_params))
51
+ end
52
+
53
+ def resource(url)
54
+ RestClient::Resource.new(url, rest_client_options)
55
+ end
56
+
57
+ # return hash
58
+ def load_json(string)
59
+ result_hash = JSON.parse(string.force_encoding("UTF-8").gsub(/[\u0011-\u001F]/, ""))
60
+ code = result_hash.delete("errcode")
61
+ en_msg = result_hash.delete("errmsg")
62
+ ResultHandler.new(code, en_msg, result_hash)
63
+ end
64
+
65
+ def endpoint_url(endpoint, url)
66
+ # 此处为了应对第三方开发者如果自助对接接口时,URL不规范的情况下,可以直接使用URL当为endpoint
67
+ return url if endpoint == CUSTOM_ENDPOINT
68
+ send("#{endpoint}_endpoint") + url
69
+ end
70
+
71
+ def plain_endpoint
72
+ "#{api_endpoint}/cgi-bin"
73
+ end
74
+
75
+ def api_endpoint
76
+ "https://api.weixin.qq.com"
77
+ end
78
+
79
+ def file_endpoint
80
+ "http://file.api.weixin.qq.com/cgi-bin"
81
+ end
82
+
83
+ def mp_endpoint(url)
84
+ "https://mp.weixin.qq.com/cgi-bin#{url}"
85
+ end
86
+
87
+ def open_endpoint(url)
88
+ "https://open.weixin.qq.com#{url}"
89
+ end
90
+
91
+ def calculate_expire(expires_in)
92
+ Time.now.to_i + expires_in.to_i - key_expired.to_i
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -0,0 +1,3 @@
1
+ Dir["#{File.dirname(__FILE__)}/api/*.rb"].each do |path|
2
+ require path
3
+ end
@@ -0,0 +1,176 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module Custom
5
+
6
+ CUSTOM_SERVICE = "https://api.weixin.qq.com/customservice".freeze
7
+
8
+ # 发送文本消息
9
+ # {
10
+ # "touser":"OPENID",
11
+ # "msgtype":"text",
12
+ # "text":
13
+ # {
14
+ # "content":"Hello World"
15
+ # }
16
+ # }
17
+ def send_text_custom(to_user, content)
18
+ message = default_options(to_user).merge({text: {content: content}})
19
+ http_post(custom_base_url, message)
20
+ end
21
+
22
+ # 发送图片消息
23
+ # {
24
+ # "touser":"OPENID",
25
+ # "msgtype":"image",
26
+ # "image":
27
+ # {
28
+ # "media_id":"MEDIA_ID"
29
+ # }
30
+ # }
31
+ def send_image_custom(to_user, media_id)
32
+ message = default_options(to_user, "image").merge({image: {media_id: media_id}})
33
+ http_post(custom_base_url, message)
34
+ end
35
+
36
+ # 发送语音消息
37
+ # {
38
+ # "touser":"OPENID",
39
+ # "msgtype":"voice",
40
+ # "voice":
41
+ # {
42
+ # "media_id":"MEDIA_ID"
43
+ # }
44
+ # }
45
+ def send_voice_custom(to_user, media_id)
46
+ message = default_options(to_user, "voice").merge({voice: {media_id: media_id}})
47
+ http_post(custom_base_url, message)
48
+ end
49
+
50
+ # 发送视频消息
51
+ # {
52
+ # "touser":"OPENID",
53
+ # "msgtype":"video",
54
+ # "video":
55
+ # {
56
+ # "media_id":"MEDIA_ID"
57
+ # }
58
+ # }
59
+ def send_video_custom(to_user, media_id, options={})
60
+ video_options = {media_id: media_id}.merge(options)
61
+ message = default_options(to_user, "video").merge({video: video_options})
62
+ http_post(custom_base_url, message)
63
+ end
64
+
65
+ # 根据media_id发送图文消息
66
+ # {
67
+ # "touser":"OPENID",
68
+ # "msgtype":"mpnews",
69
+ # "mpnews":
70
+ # {
71
+ # "media_id":"MEDIA_ID"
72
+ # }
73
+ # }
74
+ def send_mpnews_custom(to_user, media_id, options={})
75
+ mpnews_options = {media_id: media_id}.merge(options)
76
+ message = default_options(to_user, "mpnews").merge({mpnews: mpnews_options})
77
+ http_post(custom_base_url, message)
78
+ end
79
+
80
+ # 发送音乐消息
81
+ # {
82
+ # "touser":"OPENID",
83
+ # "msgtype":"music",
84
+ # "music":
85
+ # {
86
+ # "title":"MUSIC_TITLE",
87
+ # "description":"MUSIC_DESCRIPTION",
88
+ # "musicurl":"MUSIC_URL",
89
+ # "hqmusicurl":"HQ_MUSIC_URL",
90
+ # "thumb_media_id":"THUMB_MEDIA_ID"
91
+ # }
92
+ # }
93
+ def send_music_custom(to_user, media_id, musicurl, hqmusicurl, options={})
94
+ music_options = { thumb_media_id: media_id,
95
+ musicurl: musicurl,
96
+ hqmusicurl: hqmusicurl
97
+ }.merge(options)
98
+ message = default_options(to_user, "music").merge({music: music_options})
99
+ http_post(custom_base_url, message)
100
+ end
101
+
102
+ # 发送图文消息
103
+ # {
104
+ # "touser":"OPENID",
105
+ # "msgtype":"news",
106
+ # "news":{
107
+ # "articles": [
108
+ # {
109
+ # "title":"Happy Day",
110
+ # "description":"Is Really A Happy Day",
111
+ # "url":"URL",
112
+ # "picurl":"PIC_URL"
113
+ # },
114
+ # {
115
+ # "title":"Happy Day",
116
+ # "description":"Is Really A Happy Day",
117
+ # "url":"URL",
118
+ # "picurl":"PIC_URL"
119
+ # }
120
+ # ]
121
+ # }
122
+ # }
123
+ def send_news_custom(to_user, articles=[])
124
+ message = default_options(to_user, "news").merge({news: {articles: articles}})
125
+ http_post(custom_base_url, message)
126
+ end
127
+
128
+ # 官方示例:{endtime: 1439571890, pageindex: 1, pagesize: 10, starttime: 1438707864}
129
+ # options:
130
+ # page_index: 查询第几页,从1开始
131
+ # page_size: 每页大小,每页最多拉取50条
132
+ CUSTOM_RECORD_URL = "#{CUSTOM_SERVICE}/msgrecord/getrecord".freeze
133
+ def get_custom_msg_record(start_time, end_time, options={})
134
+ start_time, end_time = start_time.to_i, end_time.to_i
135
+ page_index = options[:page_index] || 1
136
+ page_size = options[:page_size] || 50
137
+ option = {
138
+ endtime: end_time,
139
+ starttime: start_time,
140
+ pageindex: page_index,
141
+ pagesize: page_size
142
+ }
143
+ http_post(CUSTOM_RECORD_URL, option, {}, CUSTOM_ENDPOINT)
144
+ end
145
+
146
+ # 客服接口创建会话
147
+ # POST数据示例如下:
148
+ # {
149
+ # "kf_account" : "test1@test",
150
+ # "openid" : "OPENID",
151
+ # "text" : "这是一段附加信息"
152
+ # }
153
+ KF_SESSION_URL = "#{CUSTOM_SERVICE}/kfsession/create".freeze
154
+ def create_kf_session(account, open_id, text)
155
+ post_body = {
156
+ kf_account: account,
157
+ openid: open_id,
158
+ text: text
159
+ }
160
+ http_post(KF_SESSION_URL, post_body, {}, CUSTOM_ENDPOINT)
161
+ end
162
+
163
+ private
164
+
165
+ # https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
166
+ def custom_base_url
167
+ "/message/custom/send"
168
+ end
169
+
170
+ def default_options(to_user, msgtype="text")
171
+ {touser: to_user, msgtype: msgtype}
172
+ end
173
+
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module DataCube
5
+
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module Groups
5
+
6
+ # 创建分组
7
+ # https://api.weixin.qq.com/cgi-bin/groups/create?access_token=ACCESS_TOKEN
8
+ def create_group(group_name)
9
+ create_url = "#{group_base_url}/create"
10
+ http_post(create_url, {group: {name: group_name}})
11
+ end
12
+
13
+ # 查询所有分组
14
+ # https://api.weixin.qq.com/cgi-bin/groups/get?access_token=ACCESS_TOKEN
15
+ def groups
16
+ groups_url = "#{group_base_url}/get"
17
+ http_get(groups_url)
18
+ end
19
+
20
+ # 查询用户所在分组
21
+ # https://api.weixin.qq.com/cgi-bin/groups/getid?access_token=ACCESS_TOKEN
22
+ def get_group_for(openid)
23
+ group_url = "#{group_base_url}/getid"
24
+ http_post(group_url, {openid: openid})
25
+ end
26
+
27
+ # 修改分组名
28
+ # https://api.weixin.qq.com/cgi-bin/groups/update?access_token=ACCESS_TOKEN
29
+ def update_group_name(group_id, new_group_name)
30
+ group_url = "#{group_base_url}/update"
31
+ http_post(group_url, {group: {id: group_id, name: new_group_name}})
32
+ end
33
+
34
+ # 移动用户分组
35
+ # https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token=ACCESS_TOKEN
36
+ def update_group_for_openid(openid, to_groupid)
37
+ group_url = "#{group_base_url}/members/update"
38
+ http_post(group_url, {openid: openid, to_groupid: to_groupid})
39
+ end
40
+
41
+ # 批量移动用户分组
42
+ def batch_update_group_for_openids(openids, group_id)
43
+ group_url = "#{group_base_url}/members/batchupdate"
44
+ http_post(group_url, {openid_list: openids, to_groupid: group_id})
45
+ end
46
+
47
+ def delete_group(group_id)
48
+ group_url = "#{group_base_url}/delete"
49
+ http_post(group_url, {group: {id: group_id}})
50
+ end
51
+
52
+ private
53
+
54
+ def group_base_url
55
+ "/groups"
56
+ end
57
+
58
+ end
59
+ end
60
+ end