magpie 0.8.6.2 → 0.8.8

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 (71) hide show
  1. data/README.md +86 -11
  2. data/Rakefile +7 -0
  3. data/bin/mag +3 -1
  4. data/lib/apps.rb +43 -0
  5. data/lib/magpie.rb +15 -25
  6. data/lib/magpie/goose.rb +88 -0
  7. data/lib/magpie/mouse.rb +43 -0
  8. data/lib/magpie/rubber.rb +16 -0
  9. data/lib/magpie/server.rb +18 -2
  10. data/lib/magpie/utils.rb +73 -22
  11. data/lib/middles/alipay.rb +3 -13
  12. data/lib/middles/chinabank.rb +3 -13
  13. data/lib/middles/snake.rb +116 -0
  14. data/lib/middles/tenpay.rb +22 -0
  15. data/lib/models/alipay.rb +96 -127
  16. data/lib/models/chinabank.rb +64 -99
  17. data/lib/models/dung.rb +66 -0
  18. data/lib/models/tenpay.rb +89 -0
  19. data/lib/views/fail.html.erb +12 -0
  20. data/lib/views/layouts/app.html.erb +42 -0
  21. data/lib/views/success.html.erb +34 -0
  22. data/magpie.gemspec +46 -4
  23. data/test/helper.rb +6 -1
  24. data/test/partner.yml +3 -0
  25. data/test/test.log +3152 -0
  26. data/test/test_alipay.rb +6 -15
  27. data/test/test_chinabank.rb +13 -5
  28. data/test/test_dung.rb +80 -0
  29. data/test/test_object.rb +18 -0
  30. data/test/test_snake.rb +55 -0
  31. data/test/test_tenpay.rb +144 -0
  32. data/test/test_utils.rb +35 -0
  33. metadata +43 -60
  34. data/doc/AlipayModel.html +0 -2010
  35. data/doc/ChinabankModel.html +0 -1245
  36. data/doc/Magpie.html +0 -255
  37. data/doc/Magpie/Alipay.html +0 -254
  38. data/doc/Magpie/Chinabank.html +0 -252
  39. data/doc/Magpie/Mothlog.html +0 -252
  40. data/doc/Magpie/Server.html +0 -241
  41. data/doc/Magpie/Server/Options.html +0 -245
  42. data/doc/Magpie/Utils.html +0 -85
  43. data/doc/_index.html +0 -186
  44. data/doc/class_list.html +0 -36
  45. data/doc/css/common.css +0 -1
  46. data/doc/css/full_list.css +0 -53
  47. data/doc/css/style.css +0 -307
  48. data/doc/file.COPYING.html +0 -78
  49. data/doc/file.README.html +0 -162
  50. data/doc/file_list.html +0 -38
  51. data/doc/frames.html +0 -13
  52. data/doc/index.html +0 -162
  53. data/doc/js/app.js +0 -202
  54. data/doc/js/full_list.js +0 -149
  55. data/doc/js/jquery.js +0 -154
  56. data/doc/method_list.html +0 -499
  57. data/doc/top-level-namespace.html +0 -90
  58. data/lib/doc/_index.html +0 -72
  59. data/lib/doc/class_list.html +0 -36
  60. data/lib/doc/css/common.css +0 -1
  61. data/lib/doc/css/full_list.css +0 -53
  62. data/lib/doc/css/style.css +0 -307
  63. data/lib/doc/file_list.html +0 -35
  64. data/lib/doc/frames.html +0 -13
  65. data/lib/doc/index.html +0 -72
  66. data/lib/doc/js/app.js +0 -202
  67. data/lib/doc/js/full_list.js +0 -149
  68. data/lib/doc/js/jquery.js +0 -154
  69. data/lib/doc/method_list.html +0 -35
  70. data/lib/doc/top-level-namespace.html +0 -78
  71. data/lib/middles/mothlog.rb +0 -33
data/README.md CHANGED
@@ -9,9 +9,9 @@ Magpie用于模拟支付平台的沙盒功能
9
9
 
10
10
  **License**: MIT License
11
11
 
12
- **Latest Version**: 0.8.6.2
12
+ **Latest Version**: 0.8.8
13
13
 
14
- **Release Date**: 2010-10-20
14
+ **Release Date**: 2010-11-03
15
15
 
16
16
 
17
17
  快搭
@@ -21,7 +21,8 @@ Magpie用于模拟支付平台的沙盒功能
21
21
  打开终端,输入:
22
22
  $ mag magpie.yml
23
23
 
24
- magpie.yml文件用来配置你的商号信息, 假设你在支付宝有个账号:123456, key是:aaabbb, 网银在线有个账号:789789, key是:cccddd, 那么你在magpie.yml中这样写,
24
+ magpie.yml文件用来配置你的商号信息, 假设你在支付宝(alipay)有个账号:123456, key是:aaabbb, 网银在线(chinabank)
25
+ 有个账号:789789, key是:cccddd, 财付通(tenpay)有个账号:888666, key是:dddggg, 那么你在magpie.yml中这样写,
25
26
 
26
27
  alipay:
27
28
  - ["123456", "aaabbb"]
@@ -29,9 +30,12 @@ magpie.yml文件用来配置你的商号信息, 假设你在支付宝有个账
29
30
  chinabank:
30
31
  - ["789789", "cccddd"]
31
32
 
33
+ tenpay:
34
+ - ["888666", "dddggg"]
35
+
32
36
  **注意!** 如果你输入mag命令报错, 那可能是因为你的电脑缺少一些magpie需要的gem包, 试着使用下面的命令:
33
37
 
34
- $ sudo gem install activemode
38
+ $ sudo gem install rack
35
39
  $ sudo gem install hpricot
36
40
 
37
41
  mag命令默认会在本地9292端口启动http服务, 你可以用-p选项指定端口
@@ -47,15 +51,80 @@ mag命令的更多选项可以通过`mag -h`查看
47
51
 
48
52
  $ mag magpie.yml
49
53
 
50
- 然后在你开发的商户系统中将支付网关由支付宝的网关`https://www.alipay.com/cooperate/gateway.do`更改为magpie的网关`http://127.0.0.1:9292/alipay`
54
+ 上面命令的意思是:用Mongrel启动magpie服务, 服务的mode是snake, 日志文件是magpie.log, 服务的端口是9292
55
+
56
+ 完整的命令是: mag -s mongrel -M snake -L magpie.log -p 9292 magpie.yml
57
+
58
+ 然后在你开发的商户系统中将支付网关由支付宝的网关`https://www.alipay.com/cooperate/gateway.do`
59
+
60
+ 更改为magpie的网关`http://127.0.0.1:9292/alipay`
61
+
62
+ 如果你请求的参数出现错误, 你可以通过magpie的日志查看到详细的出错信息, 或者在浏览器上查看出错信息
63
+
64
+ 如果你的支付请求成功, magpie将会显示一个成功订单的页面, 然后你点击购买就可以给你自己的商户系统发送
65
+
66
+ 购买成功的通知了, 你需要确保你商户系统的`notify_url`是可用的,magpie将通过这个`notify_url`将支付
67
+
68
+ 成功的通知发到你的商户系统中, 这样你就可以避免去支付宝的页面进行真实的支付.
69
+
70
+ 对于网银在线(chinabank), 将支付网关由网银在线的网关`https://pay3.chinabank.com.cn/PayGate`更改为
71
+
72
+ magpie的网关`http://127.0.0.1:9292/chinabank`
73
+
74
+ 对于财付通(tenpay), 将支付网关由财付通的网关`http://service.tenpay.com/cgi-bin/v3.0/payservice.cgi`
75
+
76
+ 更改为magpie的网关`http://127.0.0.1:9292/tenpay`
77
+
78
+
79
+ Magpie启动模式
80
+ -------------
81
+
82
+ **1. bird mode**
83
+
84
+ $ mag -M bird magpie.yml
85
+
86
+ 写ruby代码的人一般都是测试控, 这个bird模式主要是为他们提供.以支付宝(alipay)为例, 开发者将支付
87
+
88
+ 参数提交到http://127.0.0.1:9292/alipay, 出错信息将以xml格式反馈给开发者,如果提交成功, 成功
89
+
90
+ 信息同样以xml格式反馈给开发者, 同时magpie会自动将购买成功的消息通知到开发者的商户系统中,并返回
51
91
 
52
- 如果你请求的参数出现错误,你可以通过magpie的日志查看到详细的出错信息, 或者在浏览器上查看出错信息(以xml的格式显示)
92
+ 商户系统的处理结果.
53
93
 
54
- 如果你的支付请求成功magpie将会模拟支付宝的主动通知模式, 给你的商户系统发送通知, 你需要确保发送给magpie的`notify_url`
94
+ 在bird模式下,开发者需要确保magpie.yml中的商号信息是真实有效的,也就是在alipay上实际注册过的,因为
95
+
96
+ magpie在bird模式下会将开发者提交的支付参数往alipay的实际网关`https://www.alipay.com/cooperate/gateway.do`
97
+
98
+ 发送一次.
99
+
100
+ 网银在线(chinabank), 财付通(tenpay)的模拟情况与之类似.
101
+
102
+
103
+ **2. snake mode**
104
+
105
+ $ mag -M snake
106
+
107
+ 这是magpie默认的启动模式,以支付宝(alipay)为例, 开发者将支付参数提交到http://127.0.0.1:9292/alipay
108
+
109
+ 出错信息以普通html页面显示,如果提交成功, 开发者将看到订单的详细信息, 然后开发者可以点击支付按钮进行支付
110
+
111
+ 测试, 最终magpie将返回开发者商户系统的处理结果.
112
+
113
+ 网银在线(chinabank), 财付通(tenpay)的模拟情况与之类似
114
+
115
+
116
+ 其他语言开发者
117
+ ------------
118
+
119
+ 如果你使用其他开发语言, 比如php, java等,需要使用magpie, 必须首先搭建ruby执行环境才能运行mapgie.
120
+
121
+ 你可以看看这篇资料[http://www.javaeye.com/topic/43228](http://www.javaeye.com/topic/43228)
122
+
123
+ 在这篇资料,你看到"然后就可以安装rails了,"这里就可以停止了, 然后开始搭建ruby执行环境. 我鼓励你能
124
+
125
+ 把整篇资料看完, 搭建好ruby on rails开发环境, 这样你就可以用rails开发项目了.
55
126
 
56
- 是可用的,magpie将通过这个`notify_url`将支付成功的通知发到你的商户系统中, 这样你就可以避免去支付宝的页面进行真实的支付.
57
127
 
58
- 对于网银在线, 将支付网关由网银在线的网关`https://pay3.chinabank.com.cn/PayGate`更改为magpie的网关`http://127.0.0.1:9292/chinabank`
59
128
 
60
129
 
61
130
  支持的支付平台
@@ -63,6 +132,7 @@ mag命令的更多选项可以通过`mag -h`查看
63
132
 
64
133
  - 支付宝(alipay)
65
134
  - 网银在线(chinabank)
135
+ - 财付通(tenpay)
66
136
 
67
137
  使用的项目
68
138
  --------
@@ -73,7 +143,7 @@ mag命令的更多选项可以通过`mag -h`查看
73
143
  感谢
74
144
  ----
75
145
  * potian [Rack编程](http://www.javaeye.com/topic/605707)的作者
76
- * liuzihua
146
+ * liuzihua liuzihua8@gmail.com
77
147
 
78
148
 
79
149
  Changelog
@@ -81,9 +151,14 @@ Changelog
81
151
  - **2010-10-20**: 0.8.6.1 release
82
152
  - 支持网银在线
83
153
 
84
- - **2010-10-20**: 0.8.6.1 release
154
+ - **2010-10-20**: 0.8.6.2 release
85
155
  - 改善README.md的可阅读性
86
156
 
157
+ - **2010-11-03**: 0.8.8 release
158
+ - 增加财付通的支持
159
+ - 增加snake, bird两个启动模式
160
+ - 增加日志功能
161
+
87
162
 
88
163
 
89
164
  Copyright
data/Rakefile CHANGED
@@ -4,3 +4,10 @@ Rake::TestTask.new do |t|
4
4
  t.libs << "test"
5
5
  t.test_files = FileList['test/test_*.rb']
6
6
  end
7
+
8
+ task :dir_files do
9
+ files = Dir["{bin/*,lib/*,lib/magpie/**/*,lib/models/*,lib/middles/*,lib/views/**/*,test/**/*}"] -
10
+ %w(lib/magpie.yml lib/mag) +
11
+ %w(COPYING magpie.gemspec README.md Rakefile )
12
+ puts files.join("\n")
13
+ end
data/bin/mag CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
- require "magpie"
2
+ require 'magpie'
3
3
 
4
4
  Magpie::Server.start
5
+
6
+ require 'apps'
@@ -0,0 +1,43 @@
1
+
2
+
3
+ module Magpie
4
+
5
+ BIRD_APP = Rack::Builder.new {
6
+
7
+ use Rack::ContentType, "text/xml"
8
+ use Rack::ContentLength
9
+
10
+ map "/alipay" do
11
+ use Alipay
12
+ run lambda{ |env| [200, {}, [""]]}
13
+ end
14
+
15
+ map "/chinabank" do
16
+ use Chinabank
17
+ run lambda { |env| [200, {}, [""]]}
18
+ end
19
+
20
+ map "/tenpay" do
21
+ use Tenpay
22
+ run lambda { |env| [200, {}, [""]]}
23
+ end
24
+
25
+ }
26
+
27
+ SNAKE_APP = Rack::Builder.new {
28
+
29
+ use Rack::ContentType, "text/html"
30
+ use Rack::ContentLength
31
+ use Rack::Static, :urls => ["/images"], :root => File.join(Dir.pwd, "..", "static")
32
+
33
+ use Snake do |snake|
34
+ snake.tongue :alipay, :states => :index
35
+ snake.tongue :chinabank, :states => :index, :actions => :index
36
+ snake.tongue :tenpay, :states => :index, :actions => :index
37
+ snake.tongue :order, :actions => :pay
38
+ end
39
+
40
+ run lambda { |env| [200, { }, [""]]}
41
+ }
42
+
43
+ end
@@ -1,47 +1,37 @@
1
1
  # -*- coding: utf-8 -*-
2
- require 'open-uri'
3
- require 'hpricot'
4
- require 'iconv'
5
2
  require 'rack'
6
- require 'active_model'
3
+ require 'logger'
7
4
 
5
+ Object.class_eval{def blank?; self.to_s.gsub(/\s/, '').length == 0; end;}
8
6
 
9
7
  module Magpie
10
- VERSION = [0, 8, 6]
8
+
9
+ VERSION = [0, 8, 8]
10
+ FORMAT_ERRORS = %{%s : "%s" \n}
11
+ FORMAT_NOTIFY = %{Notify to [%s] %s at[%s]\n Parameters:%s\n\nBusiness result:%s\n\n}
11
12
 
12
13
  class << self
13
14
  attr_accessor :yml_db
15
+ attr_accessor :logger
14
16
 
15
17
  def version
16
18
  VERSION.join(".")
17
19
  end
18
20
  end
19
21
 
22
+ Magpie.logger = Logger.new("test/test.log") if ENV["magpie"] == 'test'
23
+
20
24
  autoload :Utils, "magpie/utils"
25
+ autoload :Rubber, "magpie/rubber"
21
26
  autoload :Mothlog, "middles/mothlog"
27
+ autoload :Snake, "middles/snake"
22
28
  autoload :Alipay, "middles/alipay"
23
29
  autoload :Chinabank, "middles/chinabank"
30
+ autoload :Tenpay, "middles/tenpay"
24
31
  autoload :Server, "magpie/server"
25
-
26
-
27
- APP = Rack::Builder.new {
28
- use Mothlog, $stderr
29
-
30
- map "/alipay" do
31
- use Alipay
32
- run lambda{ |env| [200, {"Content-Type" => "text/xml"}, [""]]}
33
- end
34
-
35
- map "/chinabank" do
36
- use Chinabank
37
- run lambda { |env| [200, { "Content-Type" => "text/xml"}, [""]]}
38
- end
39
-
40
- map "/" do
41
- run lambda{ |env| [200, {"Content-Type" => "text/html"}, ["magpie"]]}
42
- end
43
-
44
- }.to_app
32
+ autoload :Goose, "magpie/goose"
33
+ autoload :Mouse, "magpie/mouse"
34
+ autoload :Dung, "models/dung"
45
35
 
46
36
  end
47
37
 
@@ -0,0 +1,88 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Magpie
3
+ module Goose
4
+
5
+ def initialize(attributes = {})
6
+ @attributes = attributes
7
+ attributes.each do |name, value|
8
+ send("#{name}=", value) if respond_to? name
9
+ end
10
+ end
11
+
12
+ def self.included(m)
13
+ m.extend ClassMethods
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ # 用户定义验证规则
19
+ # goose_validate :be_number, :not_blank
20
+ # goose_validate do |item|
21
+ # item.errors[:name] << "名字的长度不能超过4" if item.name.length > 4
22
+ # end
23
+ # param [Array, Proc], 将验证规则添加到@validations中
24
+ def goose_validate(*ms, &p)
25
+ @validations ||= []
26
+ unless ms.to_s.length == 0
27
+ ms.each { |m| @validations << m.to_s unless @validations.member?(m.to_s)}
28
+ end
29
+ @validations << p unless p.to_s.length == 0
30
+ end
31
+
32
+ def validations
33
+ (@validations ||=[]).dup
34
+ end
35
+
36
+ def goose_validate_presence_of(*attrs)
37
+ attrs.each { |attr|
38
+ goose_validate do |am|
39
+ am.errors[attr] << "can't be blank" if am.send(attr).blank?
40
+ end
41
+ }
42
+ end
43
+
44
+ def goose_validate_format_of(*attrs)
45
+ attrs, options = parse_options(attrs)
46
+ attrs.each do |attr|
47
+ goose_validate { |am|
48
+ am.errors[attr] << (options[:msg] || "格式错误") unless am.send(attr) =~ options[:with] or (options[:allow_blank] and am.send(attr).blank?)
49
+ }
50
+ end
51
+
52
+ end
53
+
54
+ def goose_validate_length_of(*attrs)
55
+ attrs, options = parse_options attrs
56
+ min_length = options[:min_length] || 0
57
+ max_length = options[:max_length]
58
+ attrs.each do |attr|
59
+ goose_validate { |am|
60
+ attr_length = am.send(attr).to_s.length
61
+ am.errors[attr] << (options[:msg] || "长度错误") unless max_length.blank? or (attr_length >= min_length and attr_length <= max_length) or (options[:allow_blank] and am.send(attr).blank?)
62
+ }
63
+ end
64
+ end
65
+
66
+ def parse_options(attrs)
67
+ options = attrs.select{ |attr| attr.is_a? Hash}
68
+ return attrs - options, options.first
69
+ end
70
+
71
+ end
72
+
73
+ def errors
74
+ @errors ||= Hash.new{ |h, k| h[k.to_sym] = []}
75
+ end
76
+
77
+ def validating
78
+ self.class.validations.each {|v| String === v ? self.send(v) : v.call(self) }
79
+ end
80
+
81
+ def valid?
82
+ @validated ||= validating
83
+ self.errors.values.flatten.empty?
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,43 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Magpie
4
+
5
+ #获取一些持久化信息,主要是商户账号
6
+ module Mouse
7
+
8
+ class MouseError < StandardError;end
9
+
10
+ def self.included(m)
11
+ m.extend ClassMethods
12
+ end
13
+
14
+ module ClassMethods
15
+
16
+ def set_accounts_kind(kind, options={ })
17
+ @kind = kind.to_s
18
+ @accounts_env = options[:env] || "development"
19
+ end
20
+
21
+ def accounts
22
+ @accounts ||= @accounts_env == 'test' ? YAML.load_file('test/partner.yml')[@kind] : Magpie.yml_db[@kind]
23
+ raise MouseError.new("#{@kind}商号配置出错,请检查#{@kind}的商号是否配置正确") if @accounts.nil?
24
+ @accounts
25
+ end
26
+
27
+ end
28
+
29
+ def account
30
+ @account ||= self.class.accounts.assoc self.partner
31
+ @account ||= []
32
+ end
33
+
34
+ def key
35
+ @key ||= self.account[1].to_s
36
+ end
37
+
38
+ def missing_partner?
39
+ self.account == [] ? true : false
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,16 @@
1
+ module Magpie
2
+ module Rubber
3
+
4
+ def self.try(times = 1, options = { }, &block)
5
+ val = yield times
6
+ rescue options[:on] || Exception => e
7
+ Magpie.logger.info("#{Time.now}:#{__FILE__}:#{__LINE__}}:#{e.backtrace[0..8].join("\n")}")
8
+ retry if (times -= 1) > 0
9
+ raise e
10
+ else
11
+ val
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
 
2
3
  module Magpie
3
4
  class Server < Rack::Server
@@ -29,6 +30,14 @@ module Magpie
29
30
  options[:pid] = f
30
31
  }
31
32
 
33
+ opts.on("-M", "--mode MODE", "开启magpie模式选项(snake, bird 默认模式是snake)"){ |mode|
34
+ options[:mode] = mode
35
+ }
36
+
37
+ opts.on("-L", "--log logfile", "指定日志文件"){ |logfile|
38
+ options[:log] = logfile
39
+ }
40
+
32
41
  opts.separator ""
33
42
  opts.separator "Common options:"
34
43
 
@@ -49,7 +58,11 @@ module Magpie
49
58
  end
50
59
 
51
60
  def app
52
- Magpie::APP
61
+ require 'apps'
62
+ case self.options[:mode]
63
+ when "snake"; SNAKE_APP
64
+ when "bird"; BIRD_APP
65
+ end
53
66
  end
54
67
 
55
68
  def default_options
@@ -59,7 +72,9 @@ module Magpie
59
72
  :Port => 9292,
60
73
  :Host => "0.0.0.0",
61
74
  :AccessLog => [],
62
- :yml => "magpie.yml"
75
+ :yml => "magpie.yml",
76
+ :mode => "snake",
77
+ :log => "magpie.log"
63
78
  }
64
79
  end
65
80
 
@@ -74,6 +89,7 @@ module Magpie
74
89
  abort "configuration file #{options[:yml]} not found"
75
90
  end
76
91
  Magpie.yml_db = ::YAML.load_file(options[:yml])
92
+ Magpie.logger = ::Logger.new(options[:log])
77
93
  options
78
94
  end
79
95