weichat_rails 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dbde8b2fd7ae43678424029ec5a2bde7b8ee99df
4
+ data.tar.gz: 4d380976e2671b6e8b547543efb9428d356b5f15
5
+ SHA512:
6
+ metadata.gz: ae0761e2533164dfd36d6dd1fee6ff174a7fe57febeb82ef363ab0fc690a75119d23bbba3f8e464511639924ab6ac1c29b8d02ebc80b88be585bcde25d07becb
7
+ data.tar.gz: cb58481410216c5d1b4885b10ee00ed08589b97f943d06cc9e5ef22a6f0c0c0f63688060b2cda088812bf6a7b989c0546db7152ee791a2863272701444a65510
data/.gitignore ADDED
@@ -0,0 +1,18 @@
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
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in weichat_rails.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 qmliu
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,30 @@
1
+ # WeichatRails
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'weichat_rails'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install weichat_rails
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( http://github.com/<my-github-username>/weichat_rails/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
30
+ touch readme
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,34 @@
1
+ module WeichatRails
2
+ class AccessToken
3
+ attr_reader :client, :appid, :secret
4
+
5
+ CacheScope = "#{Rails.application.class.parent_name}_access_token"
6
+ def initialize(client, appid, secret)
7
+ @appid = appid
8
+ @secret = secret
9
+ @client = client
10
+ end
11
+
12
+ #store token in rails.cache
13
+ def token
14
+ Rails.cache.fetch("#{CacheScope}#{appid}",expires_in: 7200) do
15
+ data = client.get("token", params:{grant_type: "client_credential", appid: appid, secret: secret})
16
+ valid_token(data)
17
+ end
18
+ end
19
+
20
+ #delete the cache
21
+ def refresh
22
+ Rails.cache.delete("#{CacheScope}#{appid}")
23
+ end
24
+
25
+ private
26
+ def valid_token token_data
27
+ access_token = token_data["access_token"]
28
+ raise "Response didn't have access_token" if access_token.blank?
29
+ return access_token
30
+ end
31
+
32
+ end
33
+ end
34
+
@@ -0,0 +1,103 @@
1
+ require 'weichat_rails/client'
2
+ require 'weichat_rails/access_token'
3
+
4
+ class WeichatRails::Api
5
+ attr_reader :access_token, :client
6
+
7
+ API_BASE = "https://api.weixin.qq.com/cgi-bin/"
8
+ FILE_BASE = "http://file.api.weixin.qq.com/cgi-bin/"
9
+ KEFU_BASE = "https://api.weixin.qq.com/customservice/"
10
+ #https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN
11
+
12
+ def initialize appid, secret
13
+ @client = WeichatRails::Client.new(API_BASE)
14
+ @access_token = WeichatRails::AccessToken.new(@client, appid, secret)
15
+ end
16
+
17
+ def users
18
+ get("user/get")
19
+ end
20
+
21
+ def user openid
22
+ get("user/info", params:{openid: openid})
23
+ end
24
+
25
+ def menu
26
+ get("menu/get")
27
+ end
28
+
29
+ def menu_delete
30
+ get("menu/delete")
31
+ end
32
+
33
+ def kefulist
34
+ get("customservice/getkflist")
35
+ end
36
+
37
+ def group_get
38
+ get("groups/get")
39
+ end
40
+
41
+ def group_user_id openid
42
+ json_str = JSON.generate({openid: openid})
43
+ post("groups/getid", json_str)
44
+ end
45
+
46
+ def group_update openid, to_groupid
47
+ json_str = JSON.generate({openid: openid,to_groupid: to_groupid})
48
+ post("groups/members/update", json_str)
49
+ end
50
+
51
+ def get_duokefu_records time,pageindex
52
+ json_str = JSON.generate({starttime: time.beginning_of_day.to_i,endtime: time.end_of_day.to_i,pagesize: 50,pageindex: pageindex})
53
+ post("msgrecord/getrecord",json_str,base: KEFU_BASE)
54
+ end
55
+
56
+ def menu_create menu
57
+ # 微信不接受7bit escaped json(eg \uxxxx), 中文必须UTF-8编码, 这可能是个安全漏洞
58
+ # 如果是rails4.0以上使用 to_json 即可,否则使用 JSON.generate(menu,:ascii_only => false)
59
+ # 但以上试过之后仍是不行,在rails c中却是可以的,所以因该是被其它旧版本的json gem给重写了,所以采用以下方法
60
+ # 原因找到了是:
61
+ # 如果传的hash为ActiveSupport::HashWithIndifferentAccess 对像,因为用的是3.2.19,所以其编码可能不对
62
+ # 直接用 Hash对像的话,用的是ruby 2.0 的方法,做JSON.generate的时候对中文不会再编码成 \uxxxx的形式
63
+ #
64
+ json_str = JSON.generate(menu)#.gsub!(/\\u([0-9a-z]{4})/){|u| [$1.to_i(16)].pack('U')}
65
+
66
+ post("menu/create", json_str)
67
+ end
68
+
69
+ #返回媒体文件
70
+ def media media_id
71
+ get "media/get", params:{media_id: media_id}, base: FILE_BASE, as: :file
72
+ end
73
+
74
+ def media_create type, file
75
+ post "media/upload", {upload:{media: file}}, params:{type: type}, base: FILE_BASE
76
+ end
77
+
78
+ def custom_message_send message
79
+ post "message/custom/send", message.to_json, content_type: :json
80
+ end
81
+
82
+
83
+ protected
84
+ def get path, headers={}
85
+ with_access_token(headers[:params]){|params| client.get path, headers.merge(params: params)}
86
+ end
87
+
88
+ def post path, payload, headers = {}
89
+ with_access_token(headers[:params]){|params| client.post path, payload, headers.merge(params: params)}
90
+ end
91
+
92
+ def with_access_token params={}, tries=2
93
+ begin
94
+ params ||= {}
95
+ yield(params.merge(access_token: access_token.token))
96
+ rescue WeichatRails::AccessTokenExpiredError
97
+ access_token.refresh
98
+ retry unless (tries -= 1).zero?
99
+ end
100
+ end
101
+
102
+ end
103
+
@@ -0,0 +1,25 @@
1
+ module WeichatRails
2
+ module AutoGenerateSecretKey
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_create do
7
+ self.wechat_secret_key = generate_wechat_secret_key(generator: :urlsafe_base64,size: 16).downcase
8
+ self.app_token = generate_wechat_secret_key
9
+ end
10
+ end
11
+
12
+
13
+ private
14
+
15
+ def generate_wechat_secret_key(options={})
16
+ # SecureRandom: hex, base64, random_bytes, urlsafe_base64, random_number, uuid
17
+ generator_method_type = options.delete(:generator).try(:to_sym) || :hex
18
+ generator_method = SecureRandom.method(generator_method_type)
19
+ token_size = options.delete(:size).try(:to_i) || 12
20
+ return generator_method.call if generator_method_type == :uuid
21
+ generator_method.call(token_size)
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,81 @@
1
+ require 'rest_client'
2
+
3
+ module WeichatRails
4
+ class Client
5
+
6
+ attr_reader :base
7
+
8
+ def initialize(base)
9
+ @base = base
10
+ end
11
+
12
+ def get path, header={}
13
+ request(path, header) do |url, _header|
14
+ RestClient.get(url, _header)
15
+ end
16
+ end
17
+
18
+ def post path, payload, header = {}
19
+ request(path, header) do |url, _header|
20
+ RestClient.post(url, payload, _header)
21
+ end
22
+ end
23
+
24
+ def request path, header={}, &block
25
+ url = "#{header.delete(:base) || self.base}#{path}"
26
+ as = header.delete(:as)
27
+ header.merge!(:accept => :json)
28
+ response = yield(url, header)
29
+
30
+ raise "Request not OK, response code #{response.code}" if response.code != 200
31
+ parse_response(response, as || :json) do |parse_as, data|
32
+ break data unless (parse_as == :json && data["errcode"].present?)
33
+ #break data if (parse_as != :json || data["errcode"].blank?)
34
+
35
+ #如果返回的是json数据并且errcode有值,则会对errcode再做开关判断
36
+
37
+ case data["errcode"]
38
+ when 0 # for request didn't expect results
39
+ [true,data]
40
+
41
+ when 42001, 40014 #42001: access_token超时, 40014:不合法的access_token
42
+ raise AccessTokenExpiredError
43
+
44
+ when 1613189120 # for wx duokefu' msg code
45
+ [true,data]
46
+
47
+ else
48
+ raise ResponseError.new(data['errcode'], data['errmsg'])
49
+ end
50
+ end
51
+ end
52
+
53
+ private
54
+ def parse_response response, as
55
+ content_type = response.headers[:content_type]
56
+ parse_as = {
57
+ /^application\/json/ => :json,
58
+ /^image\/.*/ => :file
59
+ }.inject([]){|memo, match| memo<<match[1] if content_type =~ match[0]; memo}.first || as || :text
60
+
61
+ case parse_as
62
+ when :file
63
+ file = Tempfile.new("tmp")
64
+ file.binmode
65
+ file.write(response.body)
66
+ file.close
67
+ data = file
68
+
69
+ when :json
70
+ data = JSON.parse(response.body)
71
+
72
+ else
73
+ data = response.body
74
+ end
75
+
76
+ return yield(parse_as, data)
77
+ end
78
+
79
+ end
80
+ end
81
+
@@ -0,0 +1,170 @@
1
+ module WeichatRails
2
+ class Message
3
+
4
+ JSON_KEY_MAP = {
5
+ "ToUserName" => "touser",
6
+ "MediaId" => "media_id",
7
+ "ThumbMediaId" => "thumb_media_id"
8
+ }
9
+
10
+ class << self
11
+ def from_hash msg_hash
12
+ self.new(msg_hash)
13
+ end
14
+
15
+ def to to_user
16
+ self.new(:ToUserName=>to_user, :CreateTime=>Time.now.to_i)
17
+ end
18
+ end
19
+
20
+ class ArticleBuilder
21
+ attr_reader :items
22
+ delegate :count, to: :items
23
+ def initialize
24
+ @items=Array.new
25
+ end
26
+
27
+ def item title="title", description=nil, pic_url=nil, url=nil
28
+ items << {:Title=> title, :Description=> description, :PicUrl=> pic_url, :Url=> url}
29
+ end
30
+ end
31
+
32
+ attr_reader :message_hash
33
+
34
+ def initialize(msg_hash)
35
+ @message_hash = msg_hash || {}
36
+ end
37
+
38
+ def [](key)
39
+ message_hash[key]
40
+ end
41
+
42
+ def reply
43
+ Message.new( :ToUserName=>message_hash[:FromUserName], :FromUserName=>message_hash[:ToUserName], :CreateTime=>Time.now.to_i)
44
+ end
45
+
46
+ def as type
47
+ case type
48
+ when :text
49
+ message_hash[:Content]
50
+
51
+ when :image, :voice, :video
52
+ WeichatRails.api.media(message_hash[:MediaId])
53
+
54
+ when :location
55
+ message_hash.slice(:Location_X, :Location_Y, :Scale, :Label).inject({}){|results, value|
56
+ results[value[0].to_s.underscore.to_sym] = value[1]
57
+ results
58
+ }
59
+ else
60
+ raise "Don't know how to parse message as #{type}"
61
+ end
62
+ end
63
+
64
+ #add wechat_user for load wechat_user in proc callback
65
+ #def wechat_user user
66
+ # update(:wechat_user=>user)
67
+ #end
68
+ def kefu msg_type
69
+ update(:MsgType => msg_type)
70
+ end
71
+
72
+ def to openid
73
+ update(:ToUserName=>openid)
74
+ end
75
+
76
+ def text content
77
+ update(:MsgType=>"text", :Content=>content)
78
+ end
79
+
80
+ def image media_id
81
+ update(:MsgType=>"image", :Image=>{:MediaId=>media_id})
82
+ end
83
+
84
+ def voice media_id
85
+ update(:MsgType=>"voice", :Voice=>{:MediaId=>media_id})
86
+ end
87
+
88
+ def video media_id, opts={}
89
+ video_fields = camelize_hash_keys({media_id: media_id}.merge(opts.slice(:title, :description)))
90
+ update(:MsgType=>"video", :Video=>video_fields)
91
+ end
92
+
93
+ def music thumb_media_id, music_url, opts={}
94
+ music_fields = camelize_hash_keys(opts.slice(:title, :description, :HQ_music_url).merge(music_url: music_url, thumb_media_id: thumb_media_id))
95
+ update(:MsgType=>"music", :Music=>music_fields)
96
+ end
97
+
98
+ def news collection, &block
99
+ if block_given?
100
+ article = ArticleBuilder.new
101
+ collection.each{|item| yield(article, item)}
102
+ items = article.items
103
+ else
104
+ items = collection.collect do |item|
105
+ camelize_hash_keys(item.symbolize_keys.slice(:title, :description, :pic_url, :url))
106
+ end
107
+ end
108
+
109
+ update(:MsgType=>"news", :ArticleCount=> items.count,
110
+ :Articles=> items.collect{|item| camelize_hash_keys(item)})
111
+ end
112
+
113
+ def to_xml
114
+ message_hash.to_xml(root: "xml", children: "item", skip_instruct: true, skip_types: true)
115
+ end
116
+
117
+ def to_json
118
+ json_hash = deep_recursive(message_hash) do |key, value|
119
+ key = key.to_s
120
+ [(JSON_KEY_MAP[key] || key.downcase), value]
121
+ end
122
+
123
+ json_hash.slice!("touser", "msgtype", "content", "image", "voice", "video", "music", "news", "articles").to_hash
124
+ case json_hash["msgtype"]
125
+ when "text"
126
+ json_hash["text"] = {"content" => json_hash.delete("content")}
127
+ when "news"
128
+ json_hash["news"] = {"articles" => json_hash.delete("articles")}
129
+ end
130
+ JSON.generate(json_hash)
131
+ end
132
+
133
+ def save_to! model_class
134
+ model = model_class.new(underscore_hash_keys(message_hash))
135
+ model.save!
136
+ return self
137
+ end
138
+
139
+ private
140
+ def camelize_hash_keys hash
141
+ deep_recursive(hash){|key, value| [key.to_s.camelize.to_sym, value]}
142
+ end
143
+
144
+ def underscore_hash_keys hash
145
+ deep_recursive(hash){|key, value| [key.to_s.underscore.to_sym, value]}
146
+ end
147
+
148
+ def update fields={}
149
+ message_hash.merge!(fields)
150
+ return self
151
+ end
152
+
153
+ def deep_recursive hash, &block
154
+ hash.inject({}) do |memo, val|
155
+ key,value = *val
156
+ case value.class.name
157
+ when "Hash"
158
+ value = deep_recursive(value, &block)
159
+ when "Array"
160
+ value = value.collect{|item| item.is_a?(Hash) ? deep_recursive(item, &block) : item}
161
+ end
162
+
163
+ key,value = yield(key, value)
164
+ memo.merge!(key => value)
165
+ end
166
+ end
167
+
168
+ end
169
+ end
170
+
@@ -0,0 +1,167 @@
1
+ module WeichatRails
2
+ module Responder
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ self.before_filter :init_wechat_or_token#, only: [:show, :create]
7
+ self.skip_before_filter :verify_authenticity_token
8
+ self.before_filter :verify_signature, only: [:show, :create]
9
+ #delegate :wehcat, to: :class
10
+ end
11
+
12
+ attr_accessor :wechat, :token,:wechat_user
13
+
14
+
15
+ module ClassMethods
16
+
17
+ #定义整体的处理规则,对于不同的message_type,在block块中进行返回数据处理,
18
+ #on :text do |res,content|
19
+ #
20
+ #end
21
+ def on message_type, with: nil, respond: nil, &block
22
+ raise "Unknow message type" unless message_type.in? [:text, :image, :voice, :video, :location, :link, :event, :fallback]
23
+ config=respond.nil? ? {} : {:respond=>respond}
24
+ config.merge!(:proc=>block) if block_given?
25
+
26
+ if (with.present? && !message_type.in?([:text, :event]))
27
+ raise "Only text and event message can take :with parameters"
28
+ else
29
+ config.merge!(:with=>with) if with.present?
30
+ end
31
+
32
+ responders(message_type) << config
33
+ return config
34
+ end
35
+
36
+ def responders type
37
+ @responders ||= Hash.new
38
+ @responders[type] ||= Array.new
39
+ end
40
+
41
+
42
+ #指定的过滤方法,默认不使用指定的匹配方法,如为true,
43
+ def use_matcher mat = false
44
+ @use_matcher = mat
45
+ end
46
+
47
+ def use_matcher?
48
+ @use_matcher
49
+ end
50
+
51
+ #用于处理用户请求,该方法只关注用户信息类型及用户请求的内容或事件信息
52
+ #事件类型:subscribe(订阅)、unsubscribe(取消订阅),SCAN(关注后扫描),LOCATION(上报地理位置),CLICK(自定义菜单事件),VIEW(点击菜单跳转链接时的事件推送)
53
+ def responder_for message, &block
54
+ message_type = message[:MsgType].to_sym
55
+ responders = responders(message_type)
56
+ if use_matcher?
57
+ responder = {:method => :find_matcher}
58
+ case message_type
59
+ when :text
60
+ yield(responder,message[:Content])
61
+ when :event
62
+ yield(responder,message[:Event],message[:EventKey])
63
+ when :image,:voice,:shortvideo
64
+ yield(responder,'MEDIA',picurl: message[:PicUrl],media_id: message[:MediaId])
65
+ else
66
+ yield(responder)
67
+ end
68
+ else
69
+ case message_type
70
+ when :text
71
+ yield(* match_responders(responders, message[:Content]))
72
+ when :event
73
+ yield(* match_responders(responders, message[:Event]))
74
+ else
75
+ yield(responders.first)
76
+ end
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ #该方法用于确定预先用on定义的返回信息(一个数组 [{with:,proc:,respond:},*args])做循环处理
83
+ #responds : 预先定义的某类返回信息,类型为[:text, :image, :voice, :video, :location, :link, :event, :fallback]中之一,为一个hash数组
84
+ #value : 请求内容
85
+ #优先返回具有with值的on规则
86
+ #注:使用on定义的规则只适用于直接在控制器中写死的规则,属于类级别,不适用于后台配置类型,如果responders[msg_type]为空的情况下不产生任何内容
87
+ def match_responders responders, value
88
+ mat = responders.inject({scoped:nil, general:nil}) do |matched, responder|
89
+ condition = responder[:with]
90
+
91
+ if condition.nil?
92
+ matched[:general] ||= [responder, value]
93
+ next matched
94
+ end
95
+
96
+ if condition.is_a? Regexp
97
+ matched[:scoped] ||= [responder] + $~.captures if(value =~ condition)
98
+ else
99
+ matched[:scoped] ||= [responder, value] if(value == condition)
100
+ end
101
+ matched
102
+ end
103
+ return mat[:scoped] || mat[:general]
104
+ end
105
+ end
106
+
107
+
108
+ #用于公众号开发者中心服务器配置中的URL配置,其中xxx为该公众号在开发者数据库中的唯一识别码,由auto_generate_secret_key 来产生
109
+ #如:http://m.pipgame.com/wx/xxxxx
110
+ def show
111
+ render :text => params[:echostr]
112
+ end
113
+
114
+ #创建两个message对像,原请求message及返回message信息,返回的message中传入当前公众号对像,用于回调函数中访问该公众号在数据库中的配置信息
115
+ def create
116
+ req = WeichatRails::Message.from_hash(params[:xml] || post_xml)
117
+ #add whchat_user for multiplay wechat user
118
+ #req.wechat_user(self.wechat_user)
119
+ #如果是多客服消息,直接返回
120
+ response = self.class.responder_for(req) do |responder, *args|
121
+ responder ||= self.class.responders(:fallback).first
122
+
123
+ #next method(responder[:method]).call(*args.unshift(req)) if (responder[:method])
124
+ next if responder.nil?
125
+ next find_matcher(*args.unshift(req)) if (responder[:method])
126
+ next req.reply.text responder[:respond] if (responder[:respond])
127
+ next responder[:proc].call(*args.unshift(req)) if (responder[:proc])
128
+ end
129
+
130
+ if response.respond_to? :to_xml
131
+ render xml: response.to_xml
132
+ else
133
+ render :nothing => true, :status => 200, :content_type => 'text/html'
134
+ end
135
+ end
136
+
137
+ private
138
+ def verify_signature
139
+ array = [self.token, params[:timestamp], params[:nonce]].compact.sort
140
+ render :text => "Forbidden", :status => 403 if params[:signature] != Digest::SHA1.hexdigest(array.join)
141
+ end
142
+
143
+ def post_xml
144
+ data = Hash.from_xml(reqest.raw_post)
145
+ HashWithIndifferentAccess.new_from_hash_copying_default data.fetch('xml', {})
146
+ end
147
+
148
+
149
+ #def wechat_model
150
+ #@wechat_model || WeichatRails.config.public_account_class.constantize
151
+ #end
152
+
153
+ #TODO init wechat , wechat_user,token from database
154
+ def init_wechat_or_token
155
+ raise NotImplementedError, "controller must implement init_wechat_or_token method!if you just need reply,you can init the token,otherwise you need to init whchat and token like: wechat = Wechat::Api.new(opts[:appid], opts[:secret], opts[:access_token]) token = opts[:token]
156
+ "
157
+ end
158
+
159
+ #need to inplement
160
+ #在这里处理不同值的内容匹配:subscribe(订阅)、unsubscribe(取消订阅),SCAN(关注后扫描),LOCATION(上报地理位置),CLICK(自定义菜单事件),VIEW(点击菜单跳转链接时的事件推送)
161
+ def find_matcher(req,keyword,event_key=nil)
162
+ raise NotImplementedError, "controller must implement find_matcher method,eg: get matcher content from database"
163
+ end
164
+
165
+ end
166
+ end
167
+
@@ -0,0 +1,3 @@
1
+ module WeichatRails
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,47 @@
1
+ require "weichat_rails/api"
2
+ require "weichat_rails/auto_generate_secret_key"
3
+
4
+ module WeichatRails
5
+
6
+ autoload :Message, "weichat_rails/message"
7
+ autoload :Responder, "weichat_rails/responder"
8
+
9
+ class AccessTokenExpiredError < StandardError; end
10
+
11
+ class ResponseError < StandardError
12
+ attr_reader :error_code
13
+ def initialize(errcode, errmsg)
14
+ error_code = errcode
15
+ super "#{errmsg}(#{error_code})"
16
+ end
17
+ end
18
+
19
+
20
+ class << self
21
+ def config
22
+ @config || OpenStruct.new({wechat_secret_string: nil,wechat_token_string: nil})
23
+ end
24
+
25
+ #can configure the wechat_secret_string,wechat_token_string in weichat_rails_config.rb file
26
+ def configure
27
+ yield config if block_given?
28
+ end
29
+
30
+ end
31
+
32
+ #DEFAULT_TOKEN_COLUMN_NAME = "wechat_token".freeze
33
+ #DEFAULT_WECHAT_SECRET_KEY = "wechat_secret_key".freeze
34
+
35
+
36
+ #def self.api
37
+ # # @api ||= WechatRails::Api.new(self.config.appid, self.config.secret, self.config.access_token)
38
+ #end
39
+ end
40
+
41
+ if defined? ActionController::Base
42
+ class ActionController::Base
43
+ def self.wechat_responder opts={}
44
+ self.send(:include, WeichatRails::Responder)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'weichat_rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "weichat_rails"
8
+ spec.version = WeichatRails::VERSION
9
+ spec.authors = ["javy_liu"]
10
+ spec.email = ["javy_liu@163.com"]
11
+ spec.summary = %q{weichat interface for rails based on weichat-rails}
12
+ spec.description = %q{weichat use for more than on public weichat account,base on the mysql,~> rails 3.2.16}
13
+ spec.homepage = "https://github.com/javyliu/weichat_rails"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency "rails", "~> 3.2.14"
25
+ spec.add_dependency "nokogiri", '>=1.6.0'
26
+ spec.add_dependency 'rest-client'
27
+ spec.add_dependency 'dalli'
28
+
29
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: weichat_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - javy_liu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.2.14
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.2.14
55
+ - !ruby/object:Gem::Dependency
56
+ name: nokogiri
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.6.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 1.6.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rest-client
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: dalli
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: weichat use for more than on public weichat account,base on the mysql,~>
98
+ rails 3.2.16
99
+ email:
100
+ - javy_liu@163.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - lib/weichat_rails.rb
111
+ - lib/weichat_rails/access_token.rb
112
+ - lib/weichat_rails/api.rb
113
+ - lib/weichat_rails/auto_generate_secret_key.rb
114
+ - lib/weichat_rails/client.rb
115
+ - lib/weichat_rails/message.rb
116
+ - lib/weichat_rails/responder.rb
117
+ - lib/weichat_rails/version.rb
118
+ - weichat_rails.gemspec
119
+ homepage: https://github.com/javyliu/weichat_rails
120
+ licenses:
121
+ - MIT
122
+ metadata: {}
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.4.6
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: weichat interface for rails based on weichat-rails
143
+ test_files: []
144
+ has_rdoc: