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.
Files changed (52) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +7 -0
  4. data/.travis.yml +20 -0
  5. data/CHANGELOG.md +17 -0
  6. data/Gemfile +5 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +308 -0
  9. data/Rakefile +31 -0
  10. data/lib/config/mp_weixin_error.yml +82 -0
  11. data/lib/mp_weixin.rb +59 -0
  12. data/lib/mp_weixin/access_token.rb +172 -0
  13. data/lib/mp_weixin/client.rb +199 -0
  14. data/lib/mp_weixin/config.rb +36 -0
  15. data/lib/mp_weixin/error.rb +27 -0
  16. data/lib/mp_weixin/interface/base.rb +43 -0
  17. data/lib/mp_weixin/interface/group.rb +92 -0
  18. data/lib/mp_weixin/interface/menu.rb +73 -0
  19. data/lib/mp_weixin/interface/message.rb +38 -0
  20. data/lib/mp_weixin/interface/promotion.rb +48 -0
  21. data/lib/mp_weixin/interface/user.rb +39 -0
  22. data/lib/mp_weixin/models/event.rb +123 -0
  23. data/lib/mp_weixin/models/message.rb +227 -0
  24. data/lib/mp_weixin/models/reply_message.rb +180 -0
  25. data/lib/mp_weixin/response.rb +93 -0
  26. data/lib/mp_weixin/response_rule.rb +46 -0
  27. data/lib/mp_weixin/server.rb +39 -0
  28. data/lib/mp_weixin/server_helper.rb +94 -0
  29. data/lib/mp_weixin/version.rb +3 -0
  30. data/lib/support/active_model.rb +3 -0
  31. data/lib/support/active_model/model.rb +99 -0
  32. data/mp_weixin.gemspec +44 -0
  33. data/spec/client_spec.rb +87 -0
  34. data/spec/mp_weixin/access_token_spec.rb +140 -0
  35. data/spec/mp_weixin/client_spec.rb +111 -0
  36. data/spec/mp_weixin/config_spec.rb +24 -0
  37. data/spec/mp_weixin/interface/base_spec.rb +16 -0
  38. data/spec/mp_weixin/interface/group_spec.rb +133 -0
  39. data/spec/mp_weixin/interface/menu_spec.rb +72 -0
  40. data/spec/mp_weixin/interface/message_spec.rb +36 -0
  41. data/spec/mp_weixin/interface/promotion_spec.rb +48 -0
  42. data/spec/mp_weixin/interface/user_spec.rb +76 -0
  43. data/spec/mp_weixin/models/event_spec.rb +94 -0
  44. data/spec/mp_weixin/models/message_spec.rb +300 -0
  45. data/spec/mp_weixin/models/reply_message_spec.rb +365 -0
  46. data/spec/mp_weixin/server_helper_spec.rb +165 -0
  47. data/spec/mp_weixin/server_spec.rb +56 -0
  48. data/spec/spec_helper.rb +51 -0
  49. data/spec/support/mp_weixin.rb +7 -0
  50. data/spec/support/rspec_mixin.rb +8 -0
  51. data/spec/support/weixin.yml +12 -0
  52. 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