shixian-weixin_authorize 1.6.2
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 +18 -0
- data/.rspec +2 -0
- data/.travis.yml +11 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +22 -0
- data/README.md +67 -0
- data/Rakefile +1 -0
- data/lib/weixin_authorize/api/custom.rb +124 -0
- data/lib/weixin_authorize/api/data_cube.rb +8 -0
- data/lib/weixin_authorize/api/groups.rb +49 -0
- data/lib/weixin_authorize/api/mass.rb +78 -0
- data/lib/weixin_authorize/api/media.rb +136 -0
- data/lib/weixin_authorize/api/menu.rb +36 -0
- data/lib/weixin_authorize/api/oauth.rb +38 -0
- data/lib/weixin_authorize/api/qrcode.rb +57 -0
- data/lib/weixin_authorize/api/template.rb +34 -0
- data/lib/weixin_authorize/api/user.rb +47 -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 +86 -0
- data/lib/weixin_authorize/config.rb +29 -0
- data/lib/weixin_authorize/handler/exceptions.rb +7 -0
- data/lib/weixin_authorize/handler/global_code.rb +89 -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 +35 -0
- data/lib/weixin_authorize/token/store.rb +72 -0
- data/lib/weixin_authorize/version.rb +3 -0
- data/lib/weixin_authorize.rb +81 -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 +58 -0
- data/spec/api/groups_spec.rb +54 -0
- data/spec/api/mass_spec.rb +70 -0
- data/spec/api/media_spec.rb +70 -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.gemspec +34 -0
- metadata +202 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ddd647e674ab2c8f834c42540dee573fb95c5c333e0d19d8e9aa18ac2fb1a0c4
|
4
|
+
data.tar.gz: e8cbff4304ee920df15650f45f1bfa56c36bb4c043ec9c5eff2517afd43fb6a8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bb8604f9768539c9518f156a07e349e7e90052e555c0c83d6eb80bf3331a82e20c3266a70ec2047e6f9128f6be96682e26ecf28c3787ffaad14ef358109db595
|
7
|
+
data.tar.gz: 680c307d76fe3c5c0faf6232ac43ba66afc197fe9c734da1bada9a76e4727f0830ed2826c43556dcc59b4b769557823e7e4dd9c5acedc1d5a8956639f2c79464
|
data/.coveralls.yml
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
group :test, :development do
|
4
|
+
gem "rspec"
|
5
|
+
gem 'redis-namespace'
|
6
|
+
gem 'simplecov', '~> 0.7.1', :require => false
|
7
|
+
gem "codeclimate-test-reporter", require: nil
|
8
|
+
gem 'coveralls', require: false
|
9
|
+
# For debugger
|
10
|
+
gem "pry-rails"
|
11
|
+
|
12
|
+
gem "pry-byebug"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Specify your gem's dependencies in weixin_authorize.gemspec
|
16
|
+
gemspec
|
17
|
+
|
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,67 @@
|
|
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
|
+
* 客服消息
|
19
|
+
* 模板消息
|
20
|
+
* 用户分组管理
|
21
|
+
* 用户信息管理
|
22
|
+
* Oauth 2授权
|
23
|
+
* 二维码生成
|
24
|
+
* 自定义菜单
|
25
|
+
* 群发消息
|
26
|
+
* 多媒体管理
|
27
|
+
* JS SDK(ticket支持缓存)
|
28
|
+
|
29
|
+
## V2.0开发中:
|
30
|
+
https://github.com/lanrion/weixin_authorize/milestones/v2.0-dev
|
31
|
+
|
32
|
+
1. 重构API实现,调用方式
|
33
|
+
2. 对token,ticket的管理,提供第三方开发灵活者自助化
|
34
|
+
3. 尝试RestClient的弃用,选择更高效的HTTP client包
|
35
|
+
4. 支持更多的异常处理机制
|
36
|
+
|
37
|
+
注意:查看Wiki或者源代码时,请切换对应的版本来查看。Master处于不断更新完善分支。
|
38
|
+
|
39
|
+
## How to test
|
40
|
+
|
41
|
+
Go to https://github.com/lanrion/weixin_authorize/issues/2, apply a weixin sandbox test account and follow this account
|
42
|
+
|
43
|
+
https://github.com/lanrion/weixin_authorize/blob/master/spec/spec_helper.rb
|
44
|
+
|
45
|
+
change your infos:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
ENV["APPID"]="wxe371e0960de5426a"
|
49
|
+
ENV["APPSECRET"]="572b93d3d20aea242692a804243a141b"
|
50
|
+
ENV["OPENID"]="oEEoyuEasxionjR5HygmEOQGwRcw"
|
51
|
+
```
|
52
|
+
|
53
|
+
then run `rspec .`
|
54
|
+
|
55
|
+
## Contributing
|
56
|
+
|
57
|
+
1. Fork it
|
58
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
59
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
60
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
61
|
+
5. Create new Pull Request
|
62
|
+
|
63
|
+
## 捐赠支持
|
64
|
+
|
65
|
+
如果你觉得我的gem对你有帮助,欢迎打赏支持,:smile:
|
66
|
+
|
67
|
+

|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module WeixinAuthorize
|
3
|
+
module Api
|
4
|
+
module Custom
|
5
|
+
|
6
|
+
# 发送文本消息
|
7
|
+
# {
|
8
|
+
# "touser":"OPENID",
|
9
|
+
# "msgtype":"text",
|
10
|
+
# "text":
|
11
|
+
# {
|
12
|
+
# "content":"Hello World"
|
13
|
+
# }
|
14
|
+
# }
|
15
|
+
def send_text_custom(to_user, content)
|
16
|
+
message = default_options(to_user).merge({text: {content: content}})
|
17
|
+
http_post(custom_base_url, message)
|
18
|
+
end
|
19
|
+
|
20
|
+
# 发送图片消息
|
21
|
+
# {
|
22
|
+
# "touser":"OPENID",
|
23
|
+
# "msgtype":"image",
|
24
|
+
# "image":
|
25
|
+
# {
|
26
|
+
# "media_id":"MEDIA_ID"
|
27
|
+
# }
|
28
|
+
# }
|
29
|
+
def send_image_custom(to_user, media_id)
|
30
|
+
message = default_options(to_user, "image").merge({image: {media_id: media_id}})
|
31
|
+
http_post(custom_base_url, message)
|
32
|
+
end
|
33
|
+
|
34
|
+
# 发送语音消息
|
35
|
+
# {
|
36
|
+
# "touser":"OPENID",
|
37
|
+
# "msgtype":"voice",
|
38
|
+
# "voice":
|
39
|
+
# {
|
40
|
+
# "media_id":"MEDIA_ID"
|
41
|
+
# }
|
42
|
+
# }
|
43
|
+
def send_voice_custom(to_user, media_id)
|
44
|
+
message = default_options(to_user, "voice").merge({voice: {media_id: media_id}})
|
45
|
+
http_post(custom_base_url, message)
|
46
|
+
end
|
47
|
+
|
48
|
+
# 发送视频消息
|
49
|
+
# {
|
50
|
+
# "touser":"OPENID",
|
51
|
+
# "msgtype":"video",
|
52
|
+
# "video":
|
53
|
+
# {
|
54
|
+
# "media_id":"MEDIA_ID"
|
55
|
+
# }
|
56
|
+
# }
|
57
|
+
def send_video_custom(to_user, media_id, options={})
|
58
|
+
video_options = {media_id: media_id}.merge(options)
|
59
|
+
message = default_options(to_user, "video").merge({video: video_options})
|
60
|
+
http_post(custom_base_url, message)
|
61
|
+
end
|
62
|
+
|
63
|
+
# 发送音乐消息
|
64
|
+
# {
|
65
|
+
# "touser":"OPENID",
|
66
|
+
# "msgtype":"music",
|
67
|
+
# "music":
|
68
|
+
# {
|
69
|
+
# "title":"MUSIC_TITLE",
|
70
|
+
# "description":"MUSIC_DESCRIPTION",
|
71
|
+
# "musicurl":"MUSIC_URL",
|
72
|
+
# "hqmusicurl":"HQ_MUSIC_URL",
|
73
|
+
# "thumb_media_id":"THUMB_MEDIA_ID"
|
74
|
+
# }
|
75
|
+
# }
|
76
|
+
def send_music_custom(to_user, media_id, musicurl, hqmusicurl, options={})
|
77
|
+
music_options = { thumb_media_id: media_id,
|
78
|
+
musicurl: musicurl,
|
79
|
+
hqmusicurl: hqmusicurl
|
80
|
+
}.merge(options)
|
81
|
+
message = default_options(to_user, "music").merge({music: music_options})
|
82
|
+
http_post(custom_base_url, message)
|
83
|
+
end
|
84
|
+
|
85
|
+
# 发送图文消息
|
86
|
+
# {
|
87
|
+
# "touser":"OPENID",
|
88
|
+
# "msgtype":"news",
|
89
|
+
# "news":{
|
90
|
+
# "articles": [
|
91
|
+
# {
|
92
|
+
# "title":"Happy Day",
|
93
|
+
# "description":"Is Really A Happy Day",
|
94
|
+
# "url":"URL",
|
95
|
+
# "picurl":"PIC_URL"
|
96
|
+
# },
|
97
|
+
# {
|
98
|
+
# "title":"Happy Day",
|
99
|
+
# "description":"Is Really A Happy Day",
|
100
|
+
# "url":"URL",
|
101
|
+
# "picurl":"PIC_URL"
|
102
|
+
# }
|
103
|
+
# ]
|
104
|
+
# }
|
105
|
+
# }
|
106
|
+
def send_news_custom(to_user, articles=[])
|
107
|
+
message = default_options(to_user, "news").merge({news: {articles: articles}})
|
108
|
+
http_post(custom_base_url, message)
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
# https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
|
114
|
+
def custom_base_url
|
115
|
+
"/message/custom/send"
|
116
|
+
end
|
117
|
+
|
118
|
+
def default_options(to_user, msgtype="text")
|
119
|
+
{touser: to_user, msgtype: msgtype}
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,49 @@
|
|
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
|
+
private
|
42
|
+
|
43
|
+
def group_base_url
|
44
|
+
"/groups"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module WeixinAuthorize
|
3
|
+
module Api
|
4
|
+
module Mass
|
5
|
+
|
6
|
+
MSG_TYPE = ["mpnews", "image", "text", "voice", "mpvideo"]
|
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.to_s, "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, msgtype="mpnews")
|
37
|
+
openid_option = {"touser" => openid}
|
38
|
+
media = generate_media(msgtype, 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(msgtype, media_info, option)
|
56
|
+
msgtype = msgtype.to_s
|
57
|
+
raise "#{msgtype} is a valid msgtype" if not MSG_TYPE.include?(msgtype)
|
58
|
+
{
|
59
|
+
msgtype => convert_media_info(msgtype, media_info),
|
60
|
+
"msgtype" => msgtype
|
61
|
+
}.merge(option)
|
62
|
+
end
|
63
|
+
|
64
|
+
# 如果用户填写的media信息,是字符串,则转换来符合的数据结构,如果 是hash,则直接使用用户的结构。
|
65
|
+
def convert_media_info(msgtype, media_info)
|
66
|
+
if media_info.is_a?(String)
|
67
|
+
if msgtype == "text"
|
68
|
+
return {"content" => media_info}
|
69
|
+
else
|
70
|
+
return {"media_id" => media_info}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
media_info
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,136 @@
|
|
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
|
+
private
|
72
|
+
|
73
|
+
def media_base_url
|
74
|
+
"/media"
|
75
|
+
end
|
76
|
+
|
77
|
+
def process_file(media)
|
78
|
+
return media if media.is_a?(File) && jpep?(media)
|
79
|
+
|
80
|
+
media_url = media
|
81
|
+
uploader = WeixinUploader.new
|
82
|
+
|
83
|
+
if http?(media_url) # remote
|
84
|
+
uploader.download!(media_url.to_s)
|
85
|
+
else # local
|
86
|
+
media_file = media.is_a?(File) ? media : File.new(media_url)
|
87
|
+
uploader.cache!(media_file)
|
88
|
+
end
|
89
|
+
file = process_media(uploader)
|
90
|
+
CarrierWave.clean_cached_files! # clear last one day cache
|
91
|
+
file
|
92
|
+
end
|
93
|
+
|
94
|
+
def process_media(uploader)
|
95
|
+
uploader = covert(uploader)
|
96
|
+
uploader.file.to_file
|
97
|
+
end
|
98
|
+
|
99
|
+
# JUST ONLY FOR JPG IMAGE
|
100
|
+
def covert(uploader)
|
101
|
+
# image process
|
102
|
+
unless (uploader.file.content_type =~ /image/).nil?
|
103
|
+
if !jpep?(uploader.file)
|
104
|
+
require "mini_magick"
|
105
|
+
# covert to jpeg
|
106
|
+
image = MiniMagick::Image.open(uploader.path)
|
107
|
+
image.format("jpg")
|
108
|
+
uploader.cache!(File.open(image.path))
|
109
|
+
image.destroy! # remove /tmp from MinMagick generate
|
110
|
+
end
|
111
|
+
end
|
112
|
+
uploader
|
113
|
+
end
|
114
|
+
|
115
|
+
def http?(uri)
|
116
|
+
return false if !uri.is_a?(String)
|
117
|
+
uri = URI.parse(uri)
|
118
|
+
uri.scheme =~ /^https?$/
|
119
|
+
end
|
120
|
+
|
121
|
+
def jpep?(file)
|
122
|
+
content_type = if file.respond_to?(:content_type)
|
123
|
+
file.content_type
|
124
|
+
else
|
125
|
+
content_type(file.path)
|
126
|
+
end
|
127
|
+
!(content_type =~ /jpeg/).nil?
|
128
|
+
end
|
129
|
+
|
130
|
+
def content_type(media_path)
|
131
|
+
MIME::Types.type_for(media_path).first.content_type
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
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
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module WeixinAuthorize
|
3
|
+
module Api
|
4
|
+
module Oauth
|
5
|
+
|
6
|
+
# 应用授权作用域: scope
|
7
|
+
# snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),
|
8
|
+
# snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)
|
9
|
+
# default is snsapi_base
|
10
|
+
# state 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值
|
11
|
+
|
12
|
+
# 如果用户点击同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数redirect_uri?state=STATE
|
13
|
+
def authorize_url(redirect_uri, scope="snsapi_base", state="weixin")
|
14
|
+
require "erb"
|
15
|
+
redirect_uri = ERB::Util.url_encode(redirect_uri)
|
16
|
+
WeixinAuthorize.open_endpoint("/connect/oauth2/authorize?appid=#{app_id}&redirect_uri=#{redirect_uri}&response_type=code&scope=#{scope}&state=#{state}#wechat_redirect")
|
17
|
+
end
|
18
|
+
|
19
|
+
# 首先请注意,这里通过code换取的网页授权access_token,与基础支持中的access_token不同。公众号可通过下述接口来获取网页授权access_token。如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openid,snsapi_base式的网页授权流程即到此为止。
|
20
|
+
|
21
|
+
# 微信通过请求 #authorize_url 方法后,会返回一个code到redirect_uri中
|
22
|
+
def get_oauth_access_token(code)
|
23
|
+
WeixinAuthorize.http_get_without_token("/sns/oauth2/access_token?appid=#{app_id}&secret=#{app_secret}&code=#{code}&grant_type=authorization_code", {}, "api")
|
24
|
+
end
|
25
|
+
|
26
|
+
# refresh_token: 填写通过access_token获取到的refresh_token参数
|
27
|
+
def refresh_oauth2_token(refresh_token)
|
28
|
+
WeixinAuthorize.http_get_without_token("/sns/oauth2/refresh_token?appid=#{app_id}&grant_type=refresh_token&refresh_token=#{refresh_token}", {}, "api")
|
29
|
+
end
|
30
|
+
|
31
|
+
# 如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。
|
32
|
+
def get_oauth_userinfo(openid, oauth_token, lang="zh_CN")
|
33
|
+
WeixinAuthorize.http_get_without_token("/sns/userinfo?access_token=#{oauth_token}&openid=#{openid}&lang=#{lang}", {}, "api")
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|