wei-backend 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 +7 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +90 -0
- data/README.md +23 -0
- data/Rakefile +23 -0
- data/examples/waiting_bus/ai_bang_client.rb +17 -0
- data/examples/waiting_bus/app.rb +25 -0
- data/examples/waiting_bus/bus_helper.rb +19 -0
- data/examples/waiting_bus/config.ru +12 -0
- data/examples/waiting_bus/config/development.yml +7 -0
- data/examples/waiting_bus/config/production.yml +7 -0
- data/examples/waiting_bus/config/test.yml +7 -0
- data/examples/waiting_bus/spec/ai_bang_client_spec.rb +22 -0
- data/examples/waiting_bus/spec/bus_helper_spec.rb +19 -0
- data/examples/waiting_bus/spec/fixtures/bus_lines_response.json +44 -0
- data/lib/wei-backend.rb +3 -0
- data/lib/wei-backend/base.rb +76 -0
- data/lib/wei-backend/main.rb +23 -0
- data/lib/wei-backend/utils.rb +12 -0
- data/lib/wei-backend/version.rb +3 -0
- data/lib/wei-backend/wei-templates/image_text.haml +13 -0
- data/lib/wei-backend/wei-templates/text.haml +6 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/wei_backend_spec.rb +52 -0
- data/spec/wei_backend_utils_spec.rb +7 -0
- data/spec/weixin_message_handler_spec.rb +23 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 89c1731dc45e222e2af055b01d36d25ad34cfa71
|
4
|
+
data.tar.gz: 0d958cec757c981191d472fc29aebdac9bc42c43
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bd00720f925a9843733ac78cd680b55c2846a6d9d72555d7a3e7e40b814cb12ae468494bdb37c7d8eec5d177bd137e4b8f5db04ada1fa247616ec6be3dd34f16
|
7
|
+
data.tar.gz: 8c680f884c42ab2c0840bb53ef53b093566f95dbb2d761aacae32755c7ac9f2cfa8c93cf6989b0c81be0a506cb03402626413c27cae3f685f887a6724d8a623f
|
data/Gemfile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
|
3
|
+
gem 'json'
|
4
|
+
gem 'haml'
|
5
|
+
gem 'sinatra'
|
6
|
+
gem 'nokogiri'
|
7
|
+
gem 'capistrano'
|
8
|
+
gem 'httparty'
|
9
|
+
gem 'thin'
|
10
|
+
gem 'hash_validator'
|
11
|
+
|
12
|
+
group :test do
|
13
|
+
gem 'rspec'
|
14
|
+
gem 'rspec-html-matchers'
|
15
|
+
gem 'rack-test'
|
16
|
+
end
|
17
|
+
|
18
|
+
group :development do
|
19
|
+
gem 'rerun'
|
20
|
+
gem 'shotgun'
|
21
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
capistrano (3.0.1)
|
5
|
+
i18n
|
6
|
+
rake (>= 10.0.0)
|
7
|
+
sshkit (>= 0.0.23)
|
8
|
+
daemons (1.1.9)
|
9
|
+
diff-lcs (1.2.5)
|
10
|
+
eventmachine (1.0.3)
|
11
|
+
ffi (1.9.3)
|
12
|
+
haml (4.0.4)
|
13
|
+
tilt
|
14
|
+
hash_validator (0.2.7)
|
15
|
+
httparty (0.12.0)
|
16
|
+
json (~> 1.8)
|
17
|
+
multi_xml (>= 0.5.2)
|
18
|
+
i18n (0.6.5)
|
19
|
+
json (1.8.1)
|
20
|
+
listen (1.0.3)
|
21
|
+
rb-fsevent (>= 0.9.3)
|
22
|
+
rb-inotify (>= 0.9)
|
23
|
+
rb-kqueue (>= 0.2)
|
24
|
+
mini_portile (0.5.2)
|
25
|
+
multi_xml (0.5.5)
|
26
|
+
net-scp (1.1.2)
|
27
|
+
net-ssh (>= 2.6.5)
|
28
|
+
net-ssh (2.7.0)
|
29
|
+
nokogiri (1.6.0)
|
30
|
+
mini_portile (~> 0.5.0)
|
31
|
+
rack (1.5.2)
|
32
|
+
rack-protection (1.5.1)
|
33
|
+
rack
|
34
|
+
rack-test (0.6.2)
|
35
|
+
rack (>= 1.0)
|
36
|
+
rake (10.1.0)
|
37
|
+
rb-fsevent (0.9.3)
|
38
|
+
rb-inotify (0.9.2)
|
39
|
+
ffi (>= 0.5.0)
|
40
|
+
rb-kqueue (0.2.0)
|
41
|
+
ffi (>= 0.5.0)
|
42
|
+
rerun (0.8.2)
|
43
|
+
listen (~> 1.0.3)
|
44
|
+
rspec (2.14.1)
|
45
|
+
rspec-core (~> 2.14.0)
|
46
|
+
rspec-expectations (~> 2.14.0)
|
47
|
+
rspec-mocks (~> 2.14.0)
|
48
|
+
rspec-core (2.14.7)
|
49
|
+
rspec-expectations (2.14.4)
|
50
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
51
|
+
rspec-html-matchers (0.4.3)
|
52
|
+
nokogiri (>= 1.4.4)
|
53
|
+
rspec (>= 2.0.0)
|
54
|
+
rspec-mocks (2.14.4)
|
55
|
+
shotgun (0.9)
|
56
|
+
rack (>= 1.0)
|
57
|
+
sinatra (1.4.4)
|
58
|
+
rack (~> 1.4)
|
59
|
+
rack-protection (~> 1.4)
|
60
|
+
tilt (~> 1.3, >= 1.3.4)
|
61
|
+
sshkit (1.2.0)
|
62
|
+
net-scp (>= 1.1.2)
|
63
|
+
net-ssh
|
64
|
+
term-ansicolor
|
65
|
+
term-ansicolor (1.2.2)
|
66
|
+
tins (~> 0.8)
|
67
|
+
thin (1.6.1)
|
68
|
+
daemons (>= 1.0.9)
|
69
|
+
eventmachine (>= 1.0.0)
|
70
|
+
rack (>= 1.0.0)
|
71
|
+
tilt (1.4.1)
|
72
|
+
tins (0.13.1)
|
73
|
+
|
74
|
+
PLATFORMS
|
75
|
+
ruby
|
76
|
+
|
77
|
+
DEPENDENCIES
|
78
|
+
capistrano
|
79
|
+
haml
|
80
|
+
hash_validator
|
81
|
+
httparty
|
82
|
+
json
|
83
|
+
nokogiri
|
84
|
+
rack-test
|
85
|
+
rerun
|
86
|
+
rspec
|
87
|
+
rspec-html-matchers
|
88
|
+
shotgun
|
89
|
+
sinatra
|
90
|
+
thin
|
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
微信公众平台后台框架
|
2
|
+
========
|
3
|
+
## Ruby version:
|
4
|
+
**ruby-2.0.0-p247**
|
5
|
+
|
6
|
+
可以使用[rvm](http://rvm.io)安装:
|
7
|
+
|
8
|
+
rvm install ruby-2.0.0-p247
|
9
|
+
|
10
|
+
## 如何定制
|
11
|
+
* 启动
|
12
|
+
|
13
|
+
git clone https://github.com/charleyw/weixin-sinatra.git
|
14
|
+
bundle install
|
15
|
+
rake dev:start
|
16
|
+
* 所有的业务逻辑可以查看`lib/wei_xin_request_handler`
|
17
|
+
|
18
|
+
访问`http://localhost:9393?echostr=test`,页面会显示**echostr**的值
|
19
|
+
|
20
|
+
## 如何部署
|
21
|
+
git clone https://github.com/charleyw/weixin-sinatra.git
|
22
|
+
bundle install
|
23
|
+
rake prod:start
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
namespace :dev do
|
2
|
+
desc 'start application in local env'
|
3
|
+
task :start do
|
4
|
+
sh 'bundle exec shotgun config.ru'
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
namespace :prod do
|
9
|
+
desc 'start production'
|
10
|
+
task :start do
|
11
|
+
sh 'bundle exec thin -d -p 80 start'
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'stop production'
|
15
|
+
task :stop do
|
16
|
+
sh 'bundle exec thin stop'
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'restart production'
|
20
|
+
task :restart do
|
21
|
+
sh 'bundle exec thin restart'
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
class AiBangClient
|
5
|
+
def initialize(api_base_url, api_key)
|
6
|
+
%w(lines transfer stats).each do |category|
|
7
|
+
instance_variable_set("@#{category}_api_url", api_base_url + "/#{category}?app_key=#{api_key}&alt=json")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
def bus_lines(city, query)
|
11
|
+
encoded_city = URI.encode city
|
12
|
+
encoded_query = URI.encode query
|
13
|
+
api_url = "#{@lines_api_url}&city=#{encoded_city}&q=#{encoded_query}"
|
14
|
+
result = HTTParty.get(api_url).parsed_response["lines"]
|
15
|
+
result.has_key?('line') ? result['line'] : []
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
require './ai_bang_client'
|
4
|
+
require './bus_helper'
|
5
|
+
require_relative '../../lib/wei-backend'
|
6
|
+
|
7
|
+
CONFIG = YAML.load_file("./config/#{ENV['RACK_ENV']}.yml")
|
8
|
+
|
9
|
+
on_text do
|
10
|
+
aibang_client = AiBangClient.new CONFIG[:ai_bang_api], CONFIG[:ai_bang_api_key]
|
11
|
+
bus_helper = BusHelper.new aibang_client
|
12
|
+
bus_helper.bus_lines_running_time(params[:Content])
|
13
|
+
end
|
14
|
+
|
15
|
+
on_event do
|
16
|
+
if params[:Content].eql? 'subscribe'
|
17
|
+
CONFIG[:subscribe_message]
|
18
|
+
else
|
19
|
+
CONFIG[:unsubscribe_message]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
on_voice do
|
24
|
+
puts 'on voice message'
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class BusHelper
|
2
|
+
def initialize(ai_bang_client)
|
3
|
+
@ai_bang_client = ai_bang_client
|
4
|
+
end
|
5
|
+
|
6
|
+
def bus_lines_running_time(query)
|
7
|
+
lines = query.scan(/\w*\d+/)
|
8
|
+
bus_num = lines[0].strip if lines.length > 0
|
9
|
+
city = query.sub(/#{bus_num}.*/, '').strip
|
10
|
+
city = "西安" if city.empty?
|
11
|
+
bus_lines_results = @ai_bang_client.bus_lines(city, bus_num)
|
12
|
+
result = "";
|
13
|
+
bus_lines_results.each do |line|
|
14
|
+
running_time = line["info"].scan(/\d{1,2}[::]\d{1,2}-{1,2}\d{1,2}[::]\d{1,2}/)[0]
|
15
|
+
result += line["name"] + " " + running_time + "\n\n" if !running_time.nil?
|
16
|
+
end
|
17
|
+
result
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require_relative '../ai_bang_client'
|
3
|
+
|
4
|
+
class MockResponse
|
5
|
+
def parsed_response
|
6
|
+
JSON.parse IO.read('spec/fixtures/bus_lines_response.json')
|
7
|
+
end
|
8
|
+
end
|
9
|
+
module HTTParty
|
10
|
+
def self.get(*args, &block)
|
11
|
+
MockResponse.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'aibang api client' do
|
16
|
+
|
17
|
+
it 'should bus lines as json object when search for line 6' do
|
18
|
+
aibang_client = AiBangClient.new 'http://localhost/bus', 'api_key'
|
19
|
+
aibang_client.bus_lines("city", "query").to_s.should include "6\\u8DEF(\\u6021\\u56ED\\u8DEF\\u5317\\u53E3-\\u706B\\u8F66\\u7AD9\\u897F)"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require_relative '../ai_bang_client'
|
3
|
+
require_relative '../bus_helper'
|
4
|
+
|
5
|
+
describe "bus helper" do
|
6
|
+
|
7
|
+
it "should return bus running time when user search for line 6 running time and city is xi'an" do
|
8
|
+
aibang_client = double(AiBangClient, :bus_lines => (JSON.parse IO.read('spec/fixtures/bus_lines_response.json'))["lines"]["line"])
|
9
|
+
bus_helper = BusHelper.new aibang_client
|
10
|
+
bus_helper.bus_lines_running_time("西安6路").should include "6\u8def(\u706b\u8f66\u7ad9\u897f-\u6021\u56ed\u8def\u5317\u53e3) 6:00-20:30"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return bus running time when user search for line k700 running time and city is xi'an" do
|
14
|
+
aibang_client = double(AiBangClient, :bus_lines => (JSON.parse IO.read('spec/fixtures/bus_lines_response.json'))["lines"]["line"])
|
15
|
+
bus_helper = BusHelper.new aibang_client
|
16
|
+
bus_helper.bus_lines_running_time("西安k700路").should include "6\u8def(\u706b\u8f66\u7ad9\u897f-\u6021\u56ed\u8def\u5317\u53e3) 6:00-20:30"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
{
|
2
|
+
"result_num": "6",
|
3
|
+
"web_url": "http:\/\/bus.aibang.com",
|
4
|
+
"wap_url": "http:\/\/wap.aibang.com",
|
5
|
+
"lines": {
|
6
|
+
"line": [{
|
7
|
+
"name": "6\u8def(\u6021\u56ed\u8def\u5317\u53e3-\u706b\u8f66\u7ad9\u897f)",
|
8
|
+
"info": "\u5e02\u533a\u7ebf\u8def; \u706b\u8f66\u7ad9\u897f-\u6021\u56ed\u8def\u5317\u53e3 6:00-20:30,\u6021\u56ed\u8def\u5317\u53e3\u2014\u706b\u8f66\u7ad9\u897f 6:00-20:30; 1\u5143\u4e00\u7968\u5236 \u666e\u901a\u53610.5\u5143 \u5b66\u751f\u53610.3\u5143\u3002",
|
9
|
+
"stats": "\u6021\u56ed\u8def\u5317\u53e3;\u60a6\u56ed\u8def\u5317\u53e3;\u9526\u4e1a\u4e8c\u8def;\u4e2d\u5174\u901a\u8baf;\u5357\u4e09\u73af;\u9526\u4e1a\u8def;\u7701\u6e38\u6cf3\u4e2d\u5fc3;\u897f\u4e07\u8def\u53e3;\u6728\u5854\u5be8;\u5e02\u5efa\u56db\u516c\u53f8;\u7535\u5b50\u4e8c\u8def\u897f\u53e3;\u7535\u5b50\u5546\u57ce;\u6c99\u4e95\u6751;\u897f\u659c\u4e03\u8def;\u516c\u4ea4\u4e94\u516c\u53f8;\u897f\u659c\u516d\u8def;\u592a\u767d\u8def\u7acb\u4ea4;\u8fb9\u5bb6\u6751;\u9ec4\u96c1\u6751;\u5f20\u5bb6\u6751;\u542b\u5149\u95e8;\u5c0f\u5357\u95e8(\u4e34\u65f6\u53d6\u6d88);\u6731\u96c0\u95e8(\u4e34\u65f6\u53d6\u6d88);\u5357\u95e8(\u4e34\u65f6\u53d6\u6d88);\u949f\u697c;\u5317\u5927\u8857;\u5317\u95e8;\u897f\u95f8\u53e3\u5357\u53e3;\u706b\u8f66\u7ad9\u897f",
|
10
|
+
"stat_xys": "",
|
11
|
+
"xys": ""
|
12
|
+
}, {
|
13
|
+
"name": "6\u8def(\u706b\u8f66\u7ad9\u897f-\u6021\u56ed\u8def\u5317\u53e3)",
|
14
|
+
"info": "\u5e02\u533a\u7ebf\u8def; \u706b\u8f66\u7ad9\u897f-\u6021\u56ed\u8def\u5317\u53e3 6:00-20:30,\u6021\u56ed\u8def\u5317\u53e3\u2014\u706b\u8f66\u7ad9\u897f 6:00-20:30; 1\u5143\u4e00\u7968\u5236 \u666e\u901a\u53610.5\u5143 \u5b66\u751f\u53610.3\u5143\u3002",
|
15
|
+
"stats": "\u706b\u8f66\u7ad9\u897f;\u897f\u95f8\u53e3\u5357\u53e3;\u5317\u95e8;\u5317\u5927\u8857;\u949f\u697c;\u5357\u95e8(\u4e34\u65f6\u53d6\u6d88);\u6731\u96c0\u95e8(\u4e34\u65f6\u53d6\u6d88);\u5c0f\u5357\u95e8(\u4e34\u65f6\u53d6\u6d88);\u542b\u5149\u95e8;\u5f20\u5bb6\u6751;\u9ec4\u96c1\u6751;\u8fb9\u5bb6\u6751;\u592a\u767d\u8def\u7acb\u4ea4;\u897f\u659c\u516d\u8def;\u516c\u4ea4\u4e94\u516c\u53f8;\u897f\u659c\u4e03\u8def;\u6c99\u4e95\u6751;\u7535\u5b50\u5546\u57ce;\u7535\u5b50\u4e8c\u8def\u897f\u53e3;\u5e02\u5efa\u56db\u516c\u53f8;\u6728\u5854\u5be8;\u897f\u4e07\u8def\u53e3;\u7701\u6e38\u6cf3\u4e2d\u5fc3;\u9526\u4e1a\u8def;\u5357\u4e09\u73af;\u4e2d\u5174\u901a\u8baf;\u9526\u4e1a\u4e8c\u8def;\u60a6\u56ed\u8def\u5317\u53e3;\u6021\u56ed\u8def\u5317\u53e3",
|
16
|
+
"stat_xys": "",
|
17
|
+
"xys": ""
|
18
|
+
}, {
|
19
|
+
"name": "\u6e386(\u5510\u82d1-\u706b\u8f66\u7ad9)",
|
20
|
+
"info": "\u65c5\u6e38\u7ebf\u8def; \u706b\u8f66\u7ad9\u4e1c\u5e7f\u573a--\u5510\u82d1 6:40--19:30; \u8d77\u6b655\u89d2\uff0c5\u89d2\u8fdb\u4f4d\uff0c\u5168\u7a0b3.5\u5143\u3002",
|
21
|
+
"stats": "\u5510\u82d1;\u6797\u5e26\u8def\u91c7\u6458\u56ed;\u66f2\u6c5f\u751f\u6001\u82b1\u56ed;\u9ec4\u6e20\u5934\u6751;\u77f3\u7f8a\u519c\u5e84;\u5b5f\u6751;\u7406\u5de5\u5927\u66f2\u6c5f\u6821\u533a;\u9752\u9f99\u5bfa;\u94c1\u7089\u5e99;\u65b0\u7586\u4e09\u6240;\u89c2\u97f3\u5e99;\u5317\u6c60\u5934;\u897f\u5f71\u8def;\u5e02\u59d4\u515a\u6821;\u5927\u96c1\u5854;\u7fe0\u534e\u8def;\u5c0f\u5be8;\u5927\u5174\u5584\u5bfa(\u53d6\u6d88);\u957f\u5b89\u7acb\u4ea4(\u897f\u5b89\u97f3\u4e50\u5b66\u9662);\u7701\u4f53\u80b2\u573a(\u9655\u897f\u7701\u56fe\u4e66\u9986;\u8349\u573a\u5761;\u5357\u7a0d\u95e8;\u5357\u95e8;\u6587\u660c\u95e8;\u548c\u5e73\u95e8(\u53d6\u6d88);\u534e\u590f\u94f6\u884c;\u5927\u5dee\u5e02;\u6c11\u4e50\u56ed;\u4e94\u8def\u53e3;\u706b\u8f66\u7ad9",
|
22
|
+
"stat_xys": "",
|
23
|
+
"xys": ""
|
24
|
+
}, {
|
25
|
+
"name": "\u6e386(\u706b\u8f66\u7ad9-\u5510\u82d1)",
|
26
|
+
"info": "\u65c5\u6e38\u7ebf\u8def; \u706b\u8f66\u7ad9\u4e1c\u5e7f\u573a--\u5510\u82d1 6:40--19:30; \u8d77\u6b655\u89d2\uff0c5\u89d2\u8fdb\u4f4d\uff0c\u5168\u7a0b3.5\u5143\u3002",
|
27
|
+
"stats": "\u706b\u8f66\u7ad9;\u4e94\u8def\u53e3;\u6c11\u4e50\u56ed;\u5927\u5dee\u5e02;\u534e\u590f\u94f6\u884c;\u548c\u5e73\u95e8;\u6587\u660c\u95e8;\u5357\u95e8;\u5357\u7a0d\u95e8;\u8349\u573a\u5761;\u7701\u4f53\u80b2\u573a(\u9655\u897f\u7701\u56fe\u4e66\u9986;\u957f\u5b89\u7acb\u4ea4(\u897f\u5b89\u97f3\u4e50\u5b66\u9662);\u5927\u5174\u5584\u5bfa(\u53d6\u6d88);\u5c0f\u5be8;\u7fe0\u534e\u8def;\u5927\u96c1\u5854;\u5927\u96c1\u5854\u5357\u5e7f\u573a;\u96c1\u5f15\u8def;\u5e02\u59d4\u515a\u6821;\u897f\u5f71\u8def;\u5317\u6c60\u5934;\u89c2\u97f3\u5e99;\u65b0\u7586\u4e09\u6240;\u94c1\u7089\u5e99;\u9752\u9f99\u5bfa;\u7406\u5de5\u5927\u66f2\u6c5f\u6821\u533a;\u5b5f\u6751;\u77f3\u7f8a\u519c\u5e84;\u9ec4\u6e20\u5934\u6751;\u66f2\u6c5f\u751f\u6001\u82b1\u56ed;\u6797\u5e26\u8def\u91c7\u6458\u56ed;\u5510\u82d1",
|
28
|
+
"stat_xys": "",
|
29
|
+
"xys": ""
|
30
|
+
}, {
|
31
|
+
"name": "\u673a\u573a\u5927\u5df46\u53f7\u7ebf(\u54b8\u9633\u673a\u573a-\u5f69\u8679\u5bbe\u9986)",
|
32
|
+
"info": "\u673a\u573a:09:00-21:00;\u5f69\u8679\u5bbe\u9986:07:00-19:00;\u8d39\u7528:15\u5143+1\u5143\uff08\u71c3\u6cb9\u9644\u52a0\u8d39\uff09\/\u4eba;",
|
33
|
+
"stats": "\u54b8\u9633\u673a\u573a;\u54b8\u9633\u706b\u8f66\u7ad9;\u6e2d\u57ce\u4e2d\u5b66;\u54b8\u9633\u5e02\u653f\u5e9c;\u6c11\u751f\u5546\u53a6;\u5f69\u8679\u5bbe\u9986",
|
34
|
+
"stat_xys": "",
|
35
|
+
"xys": ""
|
36
|
+
}, {
|
37
|
+
"name": "\u673a\u573a\u5927\u5df46\u53f7\u7ebf(\u5f69\u8679\u5bbe\u9986-\u54b8\u9633\u673a\u573a)",
|
38
|
+
"info": "\u673a\u573a:09:00-21:00;\u5f69\u8679\u5bbe\u9986:07:00-19:00;\u8d39\u7528:15\u5143+1\u5143\uff08\u71c3\u6cb9\u9644\u52a0\u8d39\uff09\/\u4eba;",
|
39
|
+
"stats": "\u5f69\u8679\u5bbe\u9986;\u6c11\u751f\u5546\u53a6;\u54b8\u9633\u5e02\u653f\u5e9c;\u6e2d\u57ce\u4e2d\u5b66;\u54b8\u9633\u706b\u8f66\u7ad9;\u54b8\u9633\u673a\u573a",
|
40
|
+
"stat_xys": "",
|
41
|
+
"xys": ""
|
42
|
+
}]
|
43
|
+
}
|
44
|
+
}
|
data/lib/wei-backend.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module WeiBackend
|
2
|
+
class MessageDispatcher
|
3
|
+
attr_accessor :params
|
4
|
+
|
5
|
+
def on message_type, params
|
6
|
+
@params = params
|
7
|
+
results = send(:"handle_#{message_type.downcase}_message")
|
8
|
+
create_model results
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_model data
|
12
|
+
data.is_a?(Hash) || data.is_a?(Array) ? image_text_message(data) : text_message(data)
|
13
|
+
end
|
14
|
+
|
15
|
+
def text_message(data)
|
16
|
+
{
|
17
|
+
:format => 'text',
|
18
|
+
:model => {:content => data}.merge(account_info)
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def image_text_message model
|
23
|
+
{
|
24
|
+
:format => 'image_text',
|
25
|
+
:model => {
|
26
|
+
:article_count => model.is_a?(Array) ? model.length : 1,
|
27
|
+
:articles => model.is_a?(Array) ? model : [model]
|
28
|
+
}.merge(account_info)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def account_info
|
33
|
+
{
|
34
|
+
:myAccount => params[:ToUserName],
|
35
|
+
:userAccount => params[:FromUserName],
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.on_text &block
|
40
|
+
define_method(:handle_text_message, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.on_event &block
|
44
|
+
define_method(:handle_event_message, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.on_voice &block
|
48
|
+
define_method(:handle_voice_message, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.on_location &block
|
52
|
+
define_method(:handle_location_message, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
module Delegator
|
59
|
+
def self.delegate(*methods)
|
60
|
+
methods.each do |method_name|
|
61
|
+
define_method(method_name) do |*args, &block|
|
62
|
+
Delegator.target.send(method_name, *args, &block)
|
63
|
+
end
|
64
|
+
private method_name
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
delegate :on_text, :on_event, :on_voice, :on_location
|
69
|
+
|
70
|
+
class << self
|
71
|
+
attr_accessor :target
|
72
|
+
end
|
73
|
+
|
74
|
+
self.target = MessageDispatcher
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
get '/' do
|
5
|
+
params[:echostr]
|
6
|
+
end
|
7
|
+
|
8
|
+
post '/' do
|
9
|
+
request.body.rewind
|
10
|
+
weixin_params = WeiBackend::Utils.parse_params request.body.read
|
11
|
+
handler = WeiBackend::MessageDispatcher.new
|
12
|
+
results = handler.on weixin_params[:MsgType], weixin_params
|
13
|
+
|
14
|
+
haml results[:format].to_sym, :views => File.dirname(__FILE__)+'/wei-templates', :locals => results[:model]
|
15
|
+
end
|
16
|
+
|
17
|
+
helpers do
|
18
|
+
def cdata content
|
19
|
+
"<![CDATA[#{content}]]>"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
extend WeiBackend::Delegator
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module WeiBackend
|
2
|
+
module Utils
|
3
|
+
def self.parse_params(request_body)
|
4
|
+
doc = Nokogiri::XML::Document.parse request_body
|
5
|
+
result = {}
|
6
|
+
doc.at_css('xml').element_children.each do |child|
|
7
|
+
result[child.name.to_sym] = child.child.text
|
8
|
+
end
|
9
|
+
result
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
%xml
|
2
|
+
%ToUserName= cdata userAccount
|
3
|
+
%FromUserName= cdata myAccount
|
4
|
+
%CreateTime= cdata Time.now.to_i
|
5
|
+
%MsgType= cdata 'news'
|
6
|
+
%ArticleCount= article_count
|
7
|
+
%Articles
|
8
|
+
- articles.each do |articles|
|
9
|
+
%item
|
10
|
+
%Title= cdata articles[:title]
|
11
|
+
%Description= cdata articles[:description]
|
12
|
+
%PicUrl= cdata articles[:picture_url]
|
13
|
+
%Url= cdata articles[:url]
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'rack/test'
|
4
|
+
require 'rack'
|
5
|
+
require 'rack-protection'
|
6
|
+
require 'rspec'
|
7
|
+
require 'rspec-html-matchers'
|
8
|
+
require './lib/wei-backend'
|
9
|
+
|
10
|
+
TEXT_MESSAGE_REQUEST='<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName>'+
|
11
|
+
'<![CDATA[fromUser]]></FromUserName><CreateTime>1348831860</CreateTime><MsgType><![CDATA[text]]></MsgType>'+
|
12
|
+
'<Content><![CDATA[this is a test]]></Content><MsgId>1234567890123456</MsgId></xml>'
|
13
|
+
|
14
|
+
EVENT_MESSAGE_REQUEST='<xml><ToUserName><![CDATA[toUser]]></ToUserName>'+
|
15
|
+
'<FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>123456789</CreateTime>'+
|
16
|
+
'<MsgType><![CDATA[event]]></MsgType><Event><![CDATA[subscribe]]></Event></xml>'
|
17
|
+
|
18
|
+
PARSED_PARAMS={
|
19
|
+
:ToUserName => 'toUser',
|
20
|
+
:FromUserName => 'fromUser',
|
21
|
+
:CreateTime => '1348831860',
|
22
|
+
:MsgType => 'text',
|
23
|
+
:Content => 'this is a test',
|
24
|
+
:MsgId => '1234567890123456'
|
25
|
+
}
|
26
|
+
|
27
|
+
def app
|
28
|
+
Sinatra::Application
|
29
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
describe 'app' do
|
3
|
+
include Rack::Test::Methods
|
4
|
+
|
5
|
+
it 'should echo string when request with echostr parameter' do
|
6
|
+
get '/?echostr=test'
|
7
|
+
last_response.body.should include 'test'
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should return user defined text message when receive a text request message' do
|
11
|
+
WeiBackend::MessageDispatcher.on_text do
|
12
|
+
'hello world'
|
13
|
+
end
|
14
|
+
|
15
|
+
post '/', TEXT_MESSAGE_REQUEST, 'CONTENT_TYPE' => 'text/xml'
|
16
|
+
last_response.body.should include '<ToUserName><![CDATA[fromUser]]></ToUserName>'
|
17
|
+
last_response.body.should include '<Content><![CDATA[hello world]]></Content>'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should return user defined news message when receive a text request message' do
|
21
|
+
WeiBackend::MessageDispatcher.on_text do
|
22
|
+
{:title => 'title', :description => 'desc', :picture_url => 'pic url', :url => 'url'}
|
23
|
+
end
|
24
|
+
|
25
|
+
post '/', TEXT_MESSAGE_REQUEST, 'CONTENT_TYPE' => 'text/xml'
|
26
|
+
last_response.body.should include '<ToUserName><![CDATA[fromUser]]></ToUserName>'
|
27
|
+
last_response.body.should include '<Title><![CDATA[title]]></Title>'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should return news message when receive a text request message and user defined a multi-news' do
|
31
|
+
WeiBackend::MessageDispatcher.on_text do
|
32
|
+
[{:title => 'title', :description => 'desc', :picture_url => 'pic url', :url => 'url'},
|
33
|
+
{:title => 'title1', :description => 'desc1', :picture_url => 'pic url1', :url => 'url1'}]
|
34
|
+
end
|
35
|
+
|
36
|
+
post '/', TEXT_MESSAGE_REQUEST, 'CONTENT_TYPE' => 'text/xml'
|
37
|
+
last_response.body.should include '<ToUserName><![CDATA[fromUser]]></ToUserName>'
|
38
|
+
last_response.body.should include '<Title><![CDATA[title]]></Title>'
|
39
|
+
last_response.body.should include '<Title><![CDATA[title1]]></Title>'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should echo event request message when receive a event message' do
|
43
|
+
WeiBackend::MessageDispatcher.on_event do
|
44
|
+
'hello event'
|
45
|
+
end
|
46
|
+
|
47
|
+
post '/', EVENT_MESSAGE_REQUEST, 'CONTENT_TYPE' => 'text/xml'
|
48
|
+
last_response.body.should include '<ToUserName><![CDATA[fromUser]]></ToUserName>'
|
49
|
+
last_response.body.should include '<Content><![CDATA[hello event]]></Content>'
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../lib/wei-backend/base'
|
3
|
+
|
4
|
+
describe 'weixin message handler' do
|
5
|
+
it 'should call text message handler when invoke handle with text message' do
|
6
|
+
WeiBackend::MessageDispatcher.any_instance.should_receive(:handle_text_message) { 'results' }
|
7
|
+
dispatcher = WeiBackend::MessageDispatcher.new
|
8
|
+
dispatcher.on('text', PARSED_PARAMS).should == {:format => 'text', :model => {:content => 'results', :myAccount=>"toUser", :userAccount=>"fromUser"}}
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should return text format result when model is a string' do
|
12
|
+
dispatcher = WeiBackend::MessageDispatcher.new
|
13
|
+
dispatcher.params=PARSED_PARAMS
|
14
|
+
dispatcher.create_model('text results').should == {:format => 'text', :model => {:content => 'text results', :myAccount=>"toUser", :userAccount=>"fromUser"}}
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should return image text format result when model is a hash' do
|
18
|
+
dispatcher = WeiBackend::MessageDispatcher.new
|
19
|
+
dispatcher.params=PARSED_PARAMS
|
20
|
+
dispatcher.create_model({:url => "http://adc/"}).should == {:format=>"image_text", :model=>{:article_count=>1, :articles=>[{:url=>"http://adc/"}], :myAccount=>"toUser", :userAccount=>"fromUser"}}
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wei-backend
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Wang Chao
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sinatra
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.4.4
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.4.4
|
27
|
+
description: wei-backend is a DSL for quickly creating weixin open platform backend
|
28
|
+
system.
|
29
|
+
email: cwang8023@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- Gemfile
|
35
|
+
- Gemfile.lock
|
36
|
+
- README.md
|
37
|
+
- Rakefile
|
38
|
+
- examples/waiting_bus/ai_bang_client.rb
|
39
|
+
- examples/waiting_bus/app.rb
|
40
|
+
- examples/waiting_bus/bus_helper.rb
|
41
|
+
- examples/waiting_bus/config.ru
|
42
|
+
- examples/waiting_bus/config/development.yml
|
43
|
+
- examples/waiting_bus/config/production.yml
|
44
|
+
- examples/waiting_bus/config/test.yml
|
45
|
+
- examples/waiting_bus/spec/ai_bang_client_spec.rb
|
46
|
+
- examples/waiting_bus/spec/bus_helper_spec.rb
|
47
|
+
- examples/waiting_bus/spec/fixtures/bus_lines_response.json
|
48
|
+
- lib/wei-backend.rb
|
49
|
+
- lib/wei-backend/base.rb
|
50
|
+
- lib/wei-backend/main.rb
|
51
|
+
- lib/wei-backend/utils.rb
|
52
|
+
- lib/wei-backend/version.rb
|
53
|
+
- lib/wei-backend/wei-templates/image_text.haml
|
54
|
+
- lib/wei-backend/wei-templates/text.haml
|
55
|
+
- spec/spec_helper.rb
|
56
|
+
- spec/wei_backend_spec.rb
|
57
|
+
- spec/wei_backend_utils_spec.rb
|
58
|
+
- spec/weixin_message_handler_spec.rb
|
59
|
+
homepage:
|
60
|
+
licenses:
|
61
|
+
- MIT
|
62
|
+
metadata: {}
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 2.0.6
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: Best DSL for weixin development
|
83
|
+
test_files:
|
84
|
+
- spec/wei_backend_spec.rb
|
85
|
+
- spec/wei_backend_utils_spec.rb
|
86
|
+
- spec/weixin_message_handler_spec.rb
|