mp_weixin 0.1.0
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 +15 -0
- data/.gitignore +22 -0
- data/.rspec +7 -0
- data/.travis.yml +20 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +308 -0
- data/Rakefile +31 -0
- data/lib/config/mp_weixin_error.yml +82 -0
- data/lib/mp_weixin.rb +59 -0
- data/lib/mp_weixin/access_token.rb +172 -0
- data/lib/mp_weixin/client.rb +199 -0
- data/lib/mp_weixin/config.rb +36 -0
- data/lib/mp_weixin/error.rb +27 -0
- data/lib/mp_weixin/interface/base.rb +43 -0
- data/lib/mp_weixin/interface/group.rb +92 -0
- data/lib/mp_weixin/interface/menu.rb +73 -0
- data/lib/mp_weixin/interface/message.rb +38 -0
- data/lib/mp_weixin/interface/promotion.rb +48 -0
- data/lib/mp_weixin/interface/user.rb +39 -0
- data/lib/mp_weixin/models/event.rb +123 -0
- data/lib/mp_weixin/models/message.rb +227 -0
- data/lib/mp_weixin/models/reply_message.rb +180 -0
- data/lib/mp_weixin/response.rb +93 -0
- data/lib/mp_weixin/response_rule.rb +46 -0
- data/lib/mp_weixin/server.rb +39 -0
- data/lib/mp_weixin/server_helper.rb +94 -0
- data/lib/mp_weixin/version.rb +3 -0
- data/lib/support/active_model.rb +3 -0
- data/lib/support/active_model/model.rb +99 -0
- data/mp_weixin.gemspec +44 -0
- data/spec/client_spec.rb +87 -0
- data/spec/mp_weixin/access_token_spec.rb +140 -0
- data/spec/mp_weixin/client_spec.rb +111 -0
- data/spec/mp_weixin/config_spec.rb +24 -0
- data/spec/mp_weixin/interface/base_spec.rb +16 -0
- data/spec/mp_weixin/interface/group_spec.rb +133 -0
- data/spec/mp_weixin/interface/menu_spec.rb +72 -0
- data/spec/mp_weixin/interface/message_spec.rb +36 -0
- data/spec/mp_weixin/interface/promotion_spec.rb +48 -0
- data/spec/mp_weixin/interface/user_spec.rb +76 -0
- data/spec/mp_weixin/models/event_spec.rb +94 -0
- data/spec/mp_weixin/models/message_spec.rb +300 -0
- data/spec/mp_weixin/models/reply_message_spec.rb +365 -0
- data/spec/mp_weixin/server_helper_spec.rb +165 -0
- data/spec/mp_weixin/server_spec.rb +56 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/support/mp_weixin.rb +7 -0
- data/spec/support/rspec_mixin.rb +8 -0
- data/spec/support/weixin.yml +12 -0
- metadata +363 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module MpWeixin
|
|
2
|
+
module Config
|
|
3
|
+
|
|
4
|
+
def self.app_id= (val)
|
|
5
|
+
@@app_id = val
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.app_id
|
|
9
|
+
@@app_id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.app_secret= (val)
|
|
13
|
+
@@app_secret = val
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.app_secret
|
|
17
|
+
@@app_secret
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.url= (val)
|
|
21
|
+
@@url = val
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.url
|
|
25
|
+
@@url
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.token= (val)
|
|
29
|
+
@@token = val
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.token
|
|
33
|
+
@@token
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'multi_json'
|
|
2
|
+
require 'rack'
|
|
3
|
+
|
|
4
|
+
module MpWeixin
|
|
5
|
+
class Error < StandardError
|
|
6
|
+
attr_reader :response, :code, :description
|
|
7
|
+
|
|
8
|
+
# standard error values include:
|
|
9
|
+
# :invalid_request, :invalid_client, :invalid_token, :invalid_grant, :unsupported_grant_type, :invalid_scope
|
|
10
|
+
def initialize(response)
|
|
11
|
+
response.error = self
|
|
12
|
+
@response = response
|
|
13
|
+
|
|
14
|
+
message = []
|
|
15
|
+
|
|
16
|
+
if response.parsed.is_a?(Hash)
|
|
17
|
+
@code = response.parsed['error']
|
|
18
|
+
@description = response.parsed['error_description']
|
|
19
|
+
message << "#{@code}: #{@description}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
message << response.body
|
|
23
|
+
|
|
24
|
+
super(message.join("\n"))
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module MpWeixin
|
|
2
|
+
module Interface
|
|
3
|
+
|
|
4
|
+
# The Base class of API
|
|
5
|
+
class Base
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def default_request_params
|
|
11
|
+
access_token = @client.token.token
|
|
12
|
+
#request_params = {"oauth_consumer_key" => self.id, "access_token" => access_token, "openid" => params["openid"], "oauth_version" => "2.a", "scope" => "all"}
|
|
13
|
+
# {"appid" => @client.id, "access_token" => access_token}
|
|
14
|
+
{"access_token" => access_token}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def request(verb, path, opts={}, &block)
|
|
18
|
+
unless @client.is_authorized?
|
|
19
|
+
raise "I can't find a valid access_token. Forgot to get it or expired?"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
opts[:params] ||= {}
|
|
23
|
+
#opts[:params].merge!(default_request_params)
|
|
24
|
+
opts = ActiveSupport::HashWithIndifferentAccess.new(opts)
|
|
25
|
+
|
|
26
|
+
response = @client.token.request(verb, path, opts, &block)
|
|
27
|
+
if response.error
|
|
28
|
+
raise Error.new(response)
|
|
29
|
+
end
|
|
30
|
+
response
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def get(path, opts={}, &block)
|
|
34
|
+
request(:get, path, opts, &block)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def post(path, opts={}, &block)
|
|
38
|
+
request(:post, path, opts, &block)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module MpWeixin
|
|
3
|
+
module Interface
|
|
4
|
+
|
|
5
|
+
# 分组管理
|
|
6
|
+
#
|
|
7
|
+
# 开发者可以使用接口,对公众平台的分组进行查询、创建、修改操作,也可以使用接口在需要时移动用户到某个分组。
|
|
8
|
+
class Group < Base
|
|
9
|
+
|
|
10
|
+
# 创建分组:
|
|
11
|
+
#
|
|
12
|
+
# 一个公众账号,最多支持创建500个分组。 接口调用请求说明
|
|
13
|
+
#
|
|
14
|
+
# http请求方式: POST(请使用https协议)
|
|
15
|
+
# https://api.weixin.qq.com/cgi-bin/groups/create?access_token=ACCESS_TOKEN
|
|
16
|
+
# POST数据格式:json
|
|
17
|
+
# POST数据例子:{"group":{"name":"test"}}
|
|
18
|
+
#
|
|
19
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E5.88.9B.E5.BB.BA.E5.88.86.E7.BB.84
|
|
20
|
+
def create(arg = nil)
|
|
21
|
+
if arg.present?
|
|
22
|
+
opts = arg.is_a?(Hash) ? arg : {group: {name: arg}}
|
|
23
|
+
# JSON.generate(user_message.protocol_params, :ascii_only => true)
|
|
24
|
+
opts_json = JSON.generate(opts, :ascii_only => false)
|
|
25
|
+
|
|
26
|
+
post '/cgi-bin/groups/create', :body => opts_json, :params => default_request_params
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# 查询所有分组
|
|
31
|
+
#
|
|
32
|
+
# http请求方式: GET(请使用https协议)
|
|
33
|
+
# https://api.weixin.qq.com/cgi-bin/groups/get?access_token=ACCESS_TOKEN
|
|
34
|
+
#
|
|
35
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E6.9F.A5.E8.AF.A2.E6.89.80.E6.9C.89.E5.88.86.E7.BB.84
|
|
36
|
+
def get_groups(opts = {})
|
|
37
|
+
get '/cgi-bin/groups/get', :params => opts.merge(default_request_params)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# 查询用户所在分组
|
|
41
|
+
#
|
|
42
|
+
# 通过用户的OpenID查询其所在的GroupID。 接口调用请求说明
|
|
43
|
+
#
|
|
44
|
+
# http请求方式: POST(请使用https协议)
|
|
45
|
+
# https://api.weixin.qq.com/cgi-bin/groups/getid?access_token=ACCESS_TOKEN
|
|
46
|
+
# POST数据格式:json
|
|
47
|
+
# POST数据例子:{"openid":"od8XIjsmk6QdVTETa9jLtGWA6KBc"}
|
|
48
|
+
#
|
|
49
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E6.9F.A5.E8.AF.A2.E7.94.A8.E6.88.B7.E6.89.80.E5.9C.A8.E5.88.86.E7.BB.84
|
|
50
|
+
def getid(opts = {})
|
|
51
|
+
# JSON.generate(user_message.protocol_params, :ascii_only => true)
|
|
52
|
+
opts_json = JSON.generate(opts, :ascii_only => false) if opts.is_a?(Hash)
|
|
53
|
+
|
|
54
|
+
post '/cgi-bin/groups/getid', :body => opts_json, :params => default_request_params
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# 修改分组名
|
|
58
|
+
#
|
|
59
|
+
# 接口调用请求说明
|
|
60
|
+
#
|
|
61
|
+
# http请求方式: POST(请使用https协议)
|
|
62
|
+
# https://api.weixin.qq.com/cgi-bin/groups/update?access_token=ACCESS_TOKEN
|
|
63
|
+
# POST数据格式:json
|
|
64
|
+
# POST数据例子:{"group":{"id":108,"name":"test2_modify2"}}
|
|
65
|
+
#
|
|
66
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E4.BF.AE.E6.94.B9.E5.88.86.E7.BB.84.E5.90.8D
|
|
67
|
+
def update(opts = {})
|
|
68
|
+
# JSON.generate(user_message.protocol_params, :ascii_only => true)
|
|
69
|
+
opts_json = JSON.generate(opts, :ascii_only => false) if opts.is_a?(Hash)
|
|
70
|
+
|
|
71
|
+
post '/cgi-bin/groups/update', :body => opts_json, :params => default_request_params
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# 移动用户分组
|
|
75
|
+
#
|
|
76
|
+
# 接口调用请求说明
|
|
77
|
+
#
|
|
78
|
+
# http请求方式: POST(请使用https协议)
|
|
79
|
+
# https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token=ACCESS_TOKEN
|
|
80
|
+
# POST数据格式:json
|
|
81
|
+
# POST数据例子:{"openid":"oDF3iYx0ro3_7jD4HFRDfrjdCM58","to_groupid":108}
|
|
82
|
+
#
|
|
83
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E4.BF.AE.E6.94.B9.E5.88.86.E7.BB.84.E5.90.8D
|
|
84
|
+
def update_memgers(opts = {})
|
|
85
|
+
# JSON.generate(user_message.protocol_params, :ascii_only => true)
|
|
86
|
+
opts_json = JSON.generate(opts, :ascii_only => false) if opts.is_a?(Hash)
|
|
87
|
+
|
|
88
|
+
post '/cgi-bin/groups/members/update', :body => opts_json, :params => default_request_params
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module MpWeixin
|
|
3
|
+
module Interface
|
|
4
|
+
|
|
5
|
+
# 自定义菜单
|
|
6
|
+
class Menu < Base
|
|
7
|
+
|
|
8
|
+
# 自定义菜单创建接口:
|
|
9
|
+
#
|
|
10
|
+
# 一个公众账号,最多支持创建500个分组。 接口调用请求说明
|
|
11
|
+
#
|
|
12
|
+
# {
|
|
13
|
+
# "button":[
|
|
14
|
+
# {
|
|
15
|
+
# "type":"click",
|
|
16
|
+
# "name":"今日歌曲",
|
|
17
|
+
# "key":"V1001_TODAY_MUSIC"
|
|
18
|
+
# },
|
|
19
|
+
# {
|
|
20
|
+
# "type":"click",
|
|
21
|
+
# "name":"歌手简介",
|
|
22
|
+
# "key":"V1001_TODAY_SINGER"
|
|
23
|
+
# },
|
|
24
|
+
# {
|
|
25
|
+
# "name":"菜单",
|
|
26
|
+
# "sub_button":[
|
|
27
|
+
# {
|
|
28
|
+
# "type":"view",
|
|
29
|
+
# "name":"搜索",
|
|
30
|
+
# "url":"http://www.soso.com/"
|
|
31
|
+
# },
|
|
32
|
+
# {
|
|
33
|
+
# "type":"view",
|
|
34
|
+
# "name":"视频",
|
|
35
|
+
# "url":"http://v.qq.com/"
|
|
36
|
+
# },
|
|
37
|
+
# {
|
|
38
|
+
# "type":"click",
|
|
39
|
+
# "name":"赞一下我们",
|
|
40
|
+
# "key":"V1001_GOOD"
|
|
41
|
+
# }]
|
|
42
|
+
# }]
|
|
43
|
+
# }
|
|
44
|
+
#
|
|
45
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3
|
|
46
|
+
def create(opts = nil)
|
|
47
|
+
# JSON.generate(user_message.protocol_params, :ascii_only => true)
|
|
48
|
+
opts_json = JSON.generate(opts, :ascii_only => false) if opts.is_a?(Hash)
|
|
49
|
+
|
|
50
|
+
post '/cgi-bin/menu/create', :body => opts_json, :params => default_request_params
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# 自定义菜单查询接口
|
|
54
|
+
# http请求方式:GET
|
|
55
|
+
# https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
|
|
56
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E6%9F%A5%E8%AF%A2%E6%8E%A5%E5%8F%A3
|
|
57
|
+
def get_menus(opts = {})
|
|
58
|
+
get '/cgi-bin/menu/get', :params => opts.merge(default_request_params)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# 自定义菜单查询接口
|
|
62
|
+
# http请求方式:GET
|
|
63
|
+
# https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
|
|
64
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%A0%E9%99%A4%E6%8E%A5%E5%8F%A3
|
|
65
|
+
def delete(opts = {})
|
|
66
|
+
get '/cgi-bin/menu/delete', :params => opts.merge(default_request_params)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# 自定义菜单事件推送
|
|
70
|
+
# 用户点击自定义菜单后,如果菜单按钮设置为click类型,则微信会把此次点击事件推送给开发者,注意view类型(跳转到URL)的菜单点击不会上报。
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module MpWeixin
|
|
3
|
+
module Interface
|
|
4
|
+
|
|
5
|
+
# 发送消息
|
|
6
|
+
class Message < Base
|
|
7
|
+
# 发送客服消息
|
|
8
|
+
# 文本消息:
|
|
9
|
+
#
|
|
10
|
+
# {
|
|
11
|
+
# "touser":"OPENID",
|
|
12
|
+
# "msgtype":"text",
|
|
13
|
+
# "text":
|
|
14
|
+
# {
|
|
15
|
+
# "content":"Hello World"
|
|
16
|
+
# }
|
|
17
|
+
# }
|
|
18
|
+
#
|
|
19
|
+
# 发送图片消息:
|
|
20
|
+
# {
|
|
21
|
+
# "touser":"OPENID",
|
|
22
|
+
# "msgtype":"image",
|
|
23
|
+
# "image":
|
|
24
|
+
# {
|
|
25
|
+
# "media_id":"MEDIA_ID"
|
|
26
|
+
# }
|
|
27
|
+
# }
|
|
28
|
+
# etc
|
|
29
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF
|
|
30
|
+
def custom_send(opts = nil)
|
|
31
|
+
# JSON.generate(user_message.protocol_params, :ascii_only => true)
|
|
32
|
+
opts_json = JSON.generate(opts, :ascii_only => false) if opts.is_a?(Hash)
|
|
33
|
+
|
|
34
|
+
post '/cgi-bin/message/custom/send', :body => opts_json, :params => default_request_params
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module MpWeixin
|
|
3
|
+
module Interface
|
|
4
|
+
|
|
5
|
+
# 推广支持 生成带参数的二维码
|
|
6
|
+
class Promotion < Base
|
|
7
|
+
|
|
8
|
+
# 创建二维码ticket:
|
|
9
|
+
#
|
|
10
|
+
# 临时二维码请求说明
|
|
11
|
+
# http请求方式: POST
|
|
12
|
+
# URL: https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN
|
|
13
|
+
# POST数据格式:json
|
|
14
|
+
# POST数据例子:{"expire_seconds": 1800, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": 123}}}
|
|
15
|
+
# 永久二维码请求说明
|
|
16
|
+
# http请求方式: POST
|
|
17
|
+
# URL: https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN
|
|
18
|
+
# POST数据格式:json
|
|
19
|
+
# POST数据例子:{"action_name": "QR_LIMIT_SCENE", "action_info": {"scene": {"scene_id": 123}}}
|
|
20
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E7%94%9F%E6%88%90%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81
|
|
21
|
+
def create(opts = nil)
|
|
22
|
+
# JSON.generate(user_message.protocol_params, :ascii_only => true)
|
|
23
|
+
opts_json = JSON.generate(opts, :ascii_only => false) if opts.is_a?(Hash)
|
|
24
|
+
|
|
25
|
+
# http://rubydoc.info/gems/faraday/0.5.3/Faraday/Request
|
|
26
|
+
post '/cgi-bin/qrcode/create', :body => opts_json, :params => default_request_params
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# 自定义菜单查询接口
|
|
30
|
+
# HTTP GET请求(请使用https协议)
|
|
31
|
+
# https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET
|
|
32
|
+
# 提醒:TICKET记得进行UrlEncode
|
|
33
|
+
|
|
34
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E7%94%9F%E6%88%90%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81
|
|
35
|
+
def showqrcode(arg = nil)
|
|
36
|
+
if arg.present?
|
|
37
|
+
opts = arg.is_a?(Hash) ? arg : {ticket: arg}
|
|
38
|
+
|
|
39
|
+
get '/cgi-bin/showqrcode', :params => opts.merge(default_request_params) do |req|
|
|
40
|
+
req.url 'https://mp.weixin.qq.com/cgi-bin/showqrcode', default_request_params
|
|
41
|
+
req
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module MpWeixin
|
|
3
|
+
module Interface
|
|
4
|
+
|
|
5
|
+
# 获取用户基本信息 & 获取关注者列表
|
|
6
|
+
#
|
|
7
|
+
# 在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的。对于不同公众号,同一用户的openid不同)。公众号可通过本接口来根据OpenID获取用户基本信息,包括昵称、头像、性别、所在城市、语言和关注时间。
|
|
8
|
+
class User < Base
|
|
9
|
+
|
|
10
|
+
# 获取用户基本信息:
|
|
11
|
+
#
|
|
12
|
+
# 开发者可通过OpenID来获取用户基本信息。请使用https协议。
|
|
13
|
+
#
|
|
14
|
+
# 接口调用请求说明
|
|
15
|
+
# http请求方式: GET
|
|
16
|
+
# https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID
|
|
17
|
+
#
|
|
18
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF
|
|
19
|
+
def info(opts = {})
|
|
20
|
+
get '/cgi-bin/user/info', :params => opts.merge(default_request_params)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# 获取关注者列表
|
|
24
|
+
#
|
|
25
|
+
# 公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。
|
|
26
|
+
#
|
|
27
|
+
# http请求方式: GET(请使用https协议)
|
|
28
|
+
# https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
|
|
29
|
+
#
|
|
30
|
+
# @see http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%85%B3%E6%B3%A8%E8%80%85%E5%88%97%E8%A1%A8
|
|
31
|
+
def get_users(opts = {})
|
|
32
|
+
get '/cgi-bin/user/get', :params => opts.merge(default_request_params)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# 网页授权获取用户基本信息
|
|
36
|
+
# [prefer](https://github.com/jhjguxin/open_weixin/)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module MpWeixin
|
|
3
|
+
# The MpWeixin::Message class
|
|
4
|
+
#
|
|
5
|
+
class Event
|
|
6
|
+
include ActiveModel::Model
|
|
7
|
+
attr_accessor :ToUserName, :FromUserName,
|
|
8
|
+
:CreateTime, :MsgType
|
|
9
|
+
|
|
10
|
+
# Instantiate a new Message with a hash of attributes
|
|
11
|
+
#
|
|
12
|
+
# @param [Hash] attributes the attributes value
|
|
13
|
+
def initialize(attributes = nil)
|
|
14
|
+
# Dynamic attr_accessible
|
|
15
|
+
# maybe cause secret problem
|
|
16
|
+
singleton_class.class_eval do
|
|
17
|
+
attr_accessor *attributes.keys
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
super
|
|
21
|
+
@source = ActiveSupport::HashWithIndifferentAccess.new(attributes)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# same as @attributes CreateTime of an Message instance
|
|
25
|
+
#
|
|
26
|
+
# @return [Integer]
|
|
27
|
+
def create_time
|
|
28
|
+
self.CreateTime.to_i
|
|
29
|
+
end
|
|
30
|
+
# alias :CreateTime :create_time
|
|
31
|
+
|
|
32
|
+
# convert create_time to an Time instance
|
|
33
|
+
#
|
|
34
|
+
# @return [Time]
|
|
35
|
+
def created_at
|
|
36
|
+
Time.at create_time rescue nil
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# initialize an ReplyMessage
|
|
40
|
+
# @msg_type [string] the MsgType of ReplyMessage
|
|
41
|
+
# @attributes [Hash] the attributes of ReplyMessage
|
|
42
|
+
# @return an instance of #{MsgType}ReplyMessage
|
|
43
|
+
def reply(msg_type, attributes)
|
|
44
|
+
if attributes.is_a?(Hash)
|
|
45
|
+
attributes = attributes.deep_symbolize_keys
|
|
46
|
+
attributes.reverse_merge!({
|
|
47
|
+
ToUserName: self.FromUserName,
|
|
48
|
+
FromUserName: self.ToUserName
|
|
49
|
+
})
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
case msg_type
|
|
53
|
+
when 'text'
|
|
54
|
+
MpWeixin::TextReplyMessage.new(attributes)
|
|
55
|
+
when 'image'
|
|
56
|
+
MpWeixin::ImageReplyMessage.new(attributes)
|
|
57
|
+
when 'voice'
|
|
58
|
+
MpWeixin::VoiceReplyMessage.new(attributes)
|
|
59
|
+
when 'video'
|
|
60
|
+
MpWeixin::VideoReplyMessage.new(attributes)
|
|
61
|
+
when 'music'
|
|
62
|
+
MpWeixin::MusicReplyMessage.new(attributes)
|
|
63
|
+
when 'news'
|
|
64
|
+
MpWeixin::NewsReplyMessage.new(attributes)
|
|
65
|
+
else
|
|
66
|
+
# raise 'Unknown Message data'
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# initialize an TextReplyMessage
|
|
71
|
+
# @attributes [Hash] the attributes of TextReplyMessage
|
|
72
|
+
def reply_text_message(attributes)
|
|
73
|
+
reply("text", attributes)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# initialize an ImageReplyMessage
|
|
77
|
+
# @attributes [Hash] the attributes of ImageReplyMessage
|
|
78
|
+
def reply_image_message(attributes)
|
|
79
|
+
reply("image", attributes)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# initialize an VoiceReplyMessage
|
|
83
|
+
# @attributes [Hash] the attributes of VoiceReplyMessage
|
|
84
|
+
def reply_voice_message(attributes)
|
|
85
|
+
reply("voice", attributes)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# initialize an VideoReplyMessage
|
|
89
|
+
# @attributes [Hash] the attributes of VideoReplyMessage
|
|
90
|
+
def reply_video_message(attributes)
|
|
91
|
+
reply("video", attributes)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# initialize an MusicReplyMessage
|
|
95
|
+
# @attributes [Hash] the attributes of MusicReplyMessage
|
|
96
|
+
def reply_music_message(attributes)
|
|
97
|
+
reply("music", attributes)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# initialize an NewsReplyMessage
|
|
101
|
+
# @attributes [Hash] the attributes of NewsReplyMessage
|
|
102
|
+
def reply_news_message(attributes)
|
|
103
|
+
reply("news", attributes)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
class << self
|
|
107
|
+
def from_xml(xml)
|
|
108
|
+
begin
|
|
109
|
+
hash = MultiXml.parse(xml)['xml']
|
|
110
|
+
|
|
111
|
+
message = case hash['MsgType']
|
|
112
|
+
when 'event'
|
|
113
|
+
Event.new(hash)
|
|
114
|
+
else
|
|
115
|
+
# raise 'Unknown Message data'
|
|
116
|
+
end
|
|
117
|
+
rescue
|
|
118
|
+
logger.info('Unknown Message data #{xml}') if self.respond_to?(:logger)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|