weixin_authorize_superayi 1.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.travis.yml +11 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +72 -0
- data/Rakefile +1 -0
- data/lib/weixin_authorize/api/custom.rb +176 -0
- data/lib/weixin_authorize/api/data_cube.rb +8 -0
- data/lib/weixin_authorize/api/groups.rb +60 -0
- data/lib/weixin_authorize/api/mass.rb +80 -0
- data/lib/weixin_authorize/api/media.rb +149 -0
- data/lib/weixin_authorize/api/menu.rb +36 -0
- data/lib/weixin_authorize/api/oauth.rb +50 -0
- data/lib/weixin_authorize/api/qrcode.rb +53 -0
- data/lib/weixin_authorize/api/template.rb +43 -0
- data/lib/weixin_authorize/api/user.rb +69 -0
- data/lib/weixin_authorize/api.rb +3 -0
- data/lib/weixin_authorize/carrierwave/weixin_uploader.rb +4 -0
- data/lib/weixin_authorize/client.rb +95 -0
- data/lib/weixin_authorize/config.rb +35 -0
- data/lib/weixin_authorize/handler/exceptions.rb +5 -0
- data/lib/weixin_authorize/handler/global_code.rb +127 -0
- data/lib/weixin_authorize/handler/result_handler.rb +52 -0
- data/lib/weixin_authorize/handler.rb +3 -0
- data/lib/weixin_authorize/js_ticket/object_store.rb +21 -0
- data/lib/weixin_authorize/js_ticket/redis_store.rb +41 -0
- data/lib/weixin_authorize/js_ticket/store.rb +40 -0
- data/lib/weixin_authorize/token/object_store.rb +25 -0
- data/lib/weixin_authorize/token/redis_store.rb +38 -0
- data/lib/weixin_authorize/token/store.rb +72 -0
- data/lib/weixin_authorize/version.rb +3 -0
- data/lib/weixin_authorize.rb +97 -0
- data/spec/1_fetch_access_token_spec.rb +43 -0
- data/spec/2_fetch_jsticket_spec.rb +10 -0
- data/spec/api/custom_spec.rb +71 -0
- data/spec/api/groups_spec.rb +74 -0
- data/spec/api/mass_spec.rb +70 -0
- data/spec/api/media_spec.rb +82 -0
- data/spec/api/medias/favicon.ico +0 -0
- data/spec/api/medias/ruby-logo.jpg +0 -0
- data/spec/api/menu_spec.rb +26 -0
- data/spec/api/qrcode_spec.rb +22 -0
- data/spec/api/template_spec.rb +40 -0
- data/spec/api/user_spec.rb +26 -0
- data/spec/spec_helper.rb +130 -0
- data/weixin_authorize_superayi.gemspec +48 -0
- metadata +301 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cfb6ac26947ce643a231765a9a4bf51de165c8b0
|
4
|
+
data.tar.gz: 7acc0f884b76bfdaaae49843de26848721489c15
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b63888e6c550d4272e5f8460775026e0b7688045c48bf47b6531d57eba2af00740a9db02b93025245e867179f1489ee369b1c422bf4bdb192784e815367bb2d5
|
7
|
+
data.tar.gz: 214a03e2f36e22ef82aebe3f4b369b32b191024de04b02ecf331bab56474e0b3816261b5d9f6d725050cc249755be43f76c09383fed86e07f9575743b57f8db9
|
data/.coveralls.yml
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# WeixinAuthorize
|
2
|
+
|
3
|
+
[](http://badge.fury.io/rb/weixin_authorize)
|
4
|
+
[](http://travis-ci.org/lanrion/weixin_authorize)
|
5
|
+
[](https://codeclimate.com/github/lanrion/weixin_authorize)
|
6
|
+
[](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
|
+

|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -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,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
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module WeixinAuthorize
|
3
|
+
module Api
|
4
|
+
module Mass
|
5
|
+
|
6
|
+
MSG_TYPE = ["mpnews", "image", "text", "voice", "mpvideo"].freeze
|
7
|
+
|
8
|
+
# media_info= {"media_id" media_id}
|
9
|
+
# https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=ACCESS_TOKEN
|
10
|
+
def mass_with_group(group_id, media_info, msgtype="mpnews", is_to_all=false)
|
11
|
+
group_option = {filter: {group_id: group_id, is_to_all: is_to_all}}
|
12
|
+
media = generate_media(msgtype, media_info, group_option)
|
13
|
+
|
14
|
+
mass_url = "#{mass_base_url}/sendall"
|
15
|
+
http_post(mass_url, media)
|
16
|
+
end
|
17
|
+
|
18
|
+
# https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=ACCESS_TOKEN
|
19
|
+
# if mpvideo,
|
20
|
+
# media_info= {"media_id" => media_id, "title" => "title", "description" => "description"}
|
21
|
+
def mass_with_openids(openids, media_info, msgtype="mpnews")
|
22
|
+
openid_option = {touser: openids}
|
23
|
+
media = generate_media(msgtype, media_info, openid_option)
|
24
|
+
mass_url = "#{mass_base_url}/send"
|
25
|
+
http_post(mass_url, media)
|
26
|
+
end
|
27
|
+
|
28
|
+
# 请注意,只有已经发送成功的消息才能删除删除消息只是将消息的图文详情页失效,已经收到的用户,还是能在其本地看到消息卡片。
|
29
|
+
# 另外,删除群发消息只能删除图文消息和视频消息,其他类型的消息一经发送,无法删除。
|
30
|
+
def mass_delete_with_msgid(msg_id)
|
31
|
+
mass_url = "#{mass_base_url}/delete"
|
32
|
+
http_post(mass_url, {msg_id: msg_id})
|
33
|
+
end
|
34
|
+
|
35
|
+
# 预览接口【订阅号与服务号认证后均可用】
|
36
|
+
def mass_preview(openid, media_info, msg_type="mpnews")
|
37
|
+
openid_option = {touser: openid}
|
38
|
+
media = generate_media(msg_type, media_info, openid_option)
|
39
|
+
mass_url = "#{mass_base_url}/preview"
|
40
|
+
http_post(mass_url, media)
|
41
|
+
end
|
42
|
+
|
43
|
+
# 查询群发消息发送状态【订阅号与服务号认证后均可用】
|
44
|
+
def mass_get_status(msg_id)
|
45
|
+
mass_url = "#{mass_base_url}/get"
|
46
|
+
http_post(mass_url, {"msg_id" => msg_id})
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def mass_base_url
|
52
|
+
"/message/mass"
|
53
|
+
end
|
54
|
+
|
55
|
+
def generate_media(msg_type, media_info, option)
|
56
|
+
msg_type = msg_type.to_s
|
57
|
+
if not MSG_TYPE.include?(msg_type)
|
58
|
+
raise MediaTypeException, "#{msg_type} is a invalid msg_type"
|
59
|
+
end
|
60
|
+
{
|
61
|
+
msg_type => convert_media_info(msg_type, media_info),
|
62
|
+
"msgtype" => msg_type
|
63
|
+
}.merge(option)
|
64
|
+
end
|
65
|
+
|
66
|
+
# 如果用户填写的media信息,是字符串,则转换来符合的数据结构,如果 是hash,则直接使用用户的结构。
|
67
|
+
def convert_media_info(msg_type, media_info)
|
68
|
+
if media_info.is_a?(String)
|
69
|
+
if msg_type == "text"
|
70
|
+
return {content: media_info}
|
71
|
+
else
|
72
|
+
return {media_id: media_info}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
media_info
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module WeixinAuthorize
|
4
|
+
module Api
|
5
|
+
module Media
|
6
|
+
# 上传多媒体文件
|
7
|
+
# http请求方式: POST/FORM
|
8
|
+
# http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
|
9
|
+
# 支持传路径或者文件类型
|
10
|
+
def upload_media(media, media_type)
|
11
|
+
file = process_file(media)
|
12
|
+
upload_media_url = "#{media_base_url}/upload"
|
13
|
+
http_post(upload_media_url, {media: file}, {type: media_type}, "file")
|
14
|
+
end
|
15
|
+
|
16
|
+
# 目前仅仅把下载链接返回给第三方开发者,由第三方开发者处理下载
|
17
|
+
def download_media_url(media_id)
|
18
|
+
download_media_url = WeixinAuthorize.endpoint_url("file", "#{media_base_url}/get")
|
19
|
+
params = URI.encode_www_form("access_token" => get_access_token,
|
20
|
+
"media_id" => media_id)
|
21
|
+
download_media_url += "?#{params}"
|
22
|
+
download_media_url
|
23
|
+
end
|
24
|
+
|
25
|
+
# 上传图文消息素材, 主要用于群发消息接口
|
26
|
+
# {
|
27
|
+
# "articles": [
|
28
|
+
# {
|
29
|
+
# "thumb_media_id":"mwvBelOXCFZiq2OsIU-p",
|
30
|
+
# "author":"xxx",
|
31
|
+
# "title":"Happy Day",
|
32
|
+
# "content_source_url":"www.qq.com",
|
33
|
+
# "content":"content",
|
34
|
+
# "digest":"digest"
|
35
|
+
# },
|
36
|
+
# {
|
37
|
+
# "thumb_media_id":"mwvBelOXCFZiq2OsIU-p",
|
38
|
+
# "author":"xxx",
|
39
|
+
# "title":"Happy Day",
|
40
|
+
# "content_source_url":"www.qq.com",
|
41
|
+
# "content":"content",
|
42
|
+
# "digest":"digest"
|
43
|
+
# }
|
44
|
+
# ]
|
45
|
+
# }
|
46
|
+
# Option: author, content_source_url
|
47
|
+
def upload_mass_news(news=[])
|
48
|
+
upload_news_url = "#{media_base_url}/uploadnews"
|
49
|
+
http_post(upload_news_url, {articles: news})
|
50
|
+
end
|
51
|
+
|
52
|
+
# media_id: 需通过基础支持中的上传下载多媒体文件来得到
|
53
|
+
# https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token=ACCESS_TOKEN
|
54
|
+
|
55
|
+
# return:
|
56
|
+
# {
|
57
|
+
# "type":"video",
|
58
|
+
# "media_id":"IhdaAQXuvJtGzwwc0abfXnzeezfO0NgPK6AQYShD8RQYMTtfzbLdBIQkQziv2XJc",
|
59
|
+
# "created_at":1398848981
|
60
|
+
# }
|
61
|
+
def upload_mass_video(media_id, title="", desc="")
|
62
|
+
video_msg = {
|
63
|
+
"media_id" => media_id,
|
64
|
+
"title" => title,
|
65
|
+
"description" => desc
|
66
|
+
}
|
67
|
+
|
68
|
+
http_post("#{media_base_url}/uploadvideo", video_msg)
|
69
|
+
end
|
70
|
+
|
71
|
+
# 上传图文消息内的图片获取URL
|
72
|
+
# https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN
|
73
|
+
#
|
74
|
+
# return:
|
75
|
+
# {
|
76
|
+
# "url": "http://mmbiz.qpic.cn/mmbiz/gLO17UPS6FS2xsypf378iaNhWacZ1G1UplZYWEYfwvuU6Ont96b1roYs CNFwaRrSaKTPCUdBK9DgEHicsKwWCBRQ/0"
|
77
|
+
# }
|
78
|
+
def upload_image(image)
|
79
|
+
file = process_file(image)
|
80
|
+
upload_image_url = "#{media_base_url}/uploadimg"
|
81
|
+
http_post(upload_image_url, {media: file}, {type: 'image'}, 'file')
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def media_base_url
|
87
|
+
"/media"
|
88
|
+
end
|
89
|
+
|
90
|
+
def process_file(media)
|
91
|
+
return media if media.is_a?(File) && jpep?(media)
|
92
|
+
|
93
|
+
media_url = media
|
94
|
+
uploader = WeixinUploader.new
|
95
|
+
|
96
|
+
if http?(media_url) # remote
|
97
|
+
uploader.download!(media_url.to_s)
|
98
|
+
else # local
|
99
|
+
media_file = media.is_a?(File) ? media : File.new(media_url)
|
100
|
+
uploader.cache!(media_file)
|
101
|
+
end
|
102
|
+
file = process_media(uploader)
|
103
|
+
CarrierWave.clean_cached_files! # clear last one day cache
|
104
|
+
file
|
105
|
+
end
|
106
|
+
|
107
|
+
def process_media(uploader)
|
108
|
+
uploader = covert(uploader)
|
109
|
+
uploader.file.to_file
|
110
|
+
end
|
111
|
+
|
112
|
+
# JUST ONLY FOR JPG IMAGE
|
113
|
+
def covert(uploader)
|
114
|
+
# image process
|
115
|
+
unless (uploader.file.content_type =~ /image/).nil?
|
116
|
+
if !jpep?(uploader.file)
|
117
|
+
require "mini_magick"
|
118
|
+
# covert to jpeg
|
119
|
+
image = MiniMagick::Image.open(uploader.path)
|
120
|
+
image.format("jpg")
|
121
|
+
uploader.cache!(File.open(image.path))
|
122
|
+
image.destroy! # remove /tmp from MinMagick generate
|
123
|
+
end
|
124
|
+
end
|
125
|
+
uploader
|
126
|
+
end
|
127
|
+
|
128
|
+
def http?(uri)
|
129
|
+
return false if !uri.is_a?(String)
|
130
|
+
uri = URI.parse(uri)
|
131
|
+
uri.scheme =~ /^https?$/
|
132
|
+
end
|
133
|
+
|
134
|
+
def jpep?(file)
|
135
|
+
content_type = if file.respond_to?(:content_type)
|
136
|
+
file.content_type
|
137
|
+
else
|
138
|
+
content_type(file.path)
|
139
|
+
end
|
140
|
+
!(content_type =~ /jpeg/).nil?
|
141
|
+
end
|
142
|
+
|
143
|
+
def content_type(media_path)
|
144
|
+
MIME::Types.type_for(media_path).first.content_type
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module WeixinAuthorize
|
3
|
+
module Api
|
4
|
+
module Menu
|
5
|
+
|
6
|
+
# 自定义菜单查询接口
|
7
|
+
# https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
|
8
|
+
def menu
|
9
|
+
get_menu_url = "#{menu_base_url}/get"
|
10
|
+
http_get(get_menu_url)
|
11
|
+
end
|
12
|
+
|
13
|
+
# 自定义菜单删除接口
|
14
|
+
# https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
|
15
|
+
def delete_menu
|
16
|
+
delete_menu_url = "#{menu_base_url}/delete"
|
17
|
+
http_get(delete_menu_url)
|
18
|
+
end
|
19
|
+
|
20
|
+
# 自定义菜单创建接口
|
21
|
+
# https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
|
22
|
+
def create_menu(menu)
|
23
|
+
menu = JSON.load(menu) if menu.is_a?(String)
|
24
|
+
create_menu_url = "#{menu_base_url}/create"
|
25
|
+
http_post(create_menu_url, menu)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def menu_base_url
|
31
|
+
"/menu"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|