recurly 0.4.16 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of recurly might be problematic. Click here for more details.

Files changed (78) hide show
  1. data/README.markdown +118 -0
  2. data/bin/recurly +78 -0
  3. data/lib/rails/generators/recurly/config_generator.rb +16 -0
  4. data/lib/rails/recurly.rb +13 -0
  5. data/lib/recurly.rb +64 -139
  6. data/lib/recurly/account.rb +52 -111
  7. data/lib/recurly/add_on.rb +20 -0
  8. data/lib/recurly/adjustment.rb +51 -0
  9. data/lib/recurly/api.rb +73 -0
  10. data/lib/recurly/api/errors.rb +205 -0
  11. data/lib/recurly/api/net_http.rb +77 -0
  12. data/lib/recurly/billing_info.rb +45 -42
  13. data/lib/recurly/coupon.rb +63 -8
  14. data/lib/recurly/helper.rb +39 -0
  15. data/lib/recurly/invoice.rb +38 -16
  16. data/lib/recurly/js.rb +113 -0
  17. data/lib/recurly/money.rb +105 -0
  18. data/lib/recurly/plan.rb +26 -15
  19. data/lib/recurly/redemption.rb +34 -0
  20. data/lib/recurly/resource.rb +925 -0
  21. data/lib/recurly/resource/pager.rb +210 -0
  22. data/lib/recurly/subscription.rb +90 -67
  23. data/lib/recurly/subscription/add_ons.rb +73 -0
  24. data/lib/recurly/transaction.rb +65 -53
  25. data/lib/recurly/transaction/errors.rb +98 -0
  26. data/lib/recurly/version.rb +16 -2
  27. data/lib/recurly/xml.rb +85 -0
  28. data/lib/recurly/xml/nokogiri.rb +49 -0
  29. data/lib/recurly/xml/rexml.rb +50 -0
  30. metadata +76 -165
  31. data/LICENSE +0 -21
  32. data/README.md +0 -104
  33. data/init.rb +0 -1
  34. data/lib/patches/rails2/active_resource/base.rb +0 -35
  35. data/lib/patches/rails2/active_resource/connection.rb +0 -10
  36. data/lib/patches/rails3/active_model/serializers/xml.rb +0 -28
  37. data/lib/patches/rails3/active_resource/connection.rb +0 -10
  38. data/lib/recurly/account_base.rb +0 -35
  39. data/lib/recurly/base.rb +0 -195
  40. data/lib/recurly/charge.rb +0 -39
  41. data/lib/recurly/config_parser.rb +0 -31
  42. data/lib/recurly/credit.rb +0 -28
  43. data/lib/recurly/exceptions.rb +0 -32
  44. data/lib/recurly/formats/xml_with_errors.rb +0 -132
  45. data/lib/recurly/formats/xml_with_pagination.rb +0 -47
  46. data/lib/recurly/rails2/compatibility.rb +0 -8
  47. data/lib/recurly/rails3/railtie.rb +0 -21
  48. data/lib/recurly/rails3/recurly.rake +0 -28
  49. data/lib/recurly/transparent.rb +0 -148
  50. data/lib/recurly/verification.rb +0 -83
  51. data/spec/config/recurly.yml +0 -6
  52. data/spec/config/test1.yml +0 -4
  53. data/spec/config/test2.yml +0 -7
  54. data/spec/integration/account_spec.rb +0 -286
  55. data/spec/integration/add_on_spec.rb +0 -84
  56. data/spec/integration/billing_info_spec.rb +0 -148
  57. data/spec/integration/charge_spec.rb +0 -176
  58. data/spec/integration/coupon_spec.rb +0 -49
  59. data/spec/integration/credit_spec.rb +0 -106
  60. data/spec/integration/invoice_spec.rb +0 -86
  61. data/spec/integration/plan_spec.rb +0 -87
  62. data/spec/integration/subscription_spec.rb +0 -221
  63. data/spec/integration/transaction_spec.rb +0 -154
  64. data/spec/integration/transparent_spec.rb +0 -99
  65. data/spec/spec_helper.rb +0 -34
  66. data/spec/support/factory.rb +0 -211
  67. data/spec/support/vcr.rb +0 -11
  68. data/spec/unit/account_spec.rb +0 -19
  69. data/spec/unit/billing_info_spec.rb +0 -39
  70. data/spec/unit/charge_spec.rb +0 -20
  71. data/spec/unit/config_spec.rb +0 -42
  72. data/spec/unit/coupon_spec.rb +0 -13
  73. data/spec/unit/credit_spec.rb +0 -20
  74. data/spec/unit/plan_spec.rb +0 -18
  75. data/spec/unit/subscription_spec.rb +0 -25
  76. data/spec/unit/transaction_spec.rb +0 -32
  77. data/spec/unit/transparent_spec.rb +0 -152
  78. data/spec/unit/verification_spec.rb +0 -82
@@ -1,83 +0,0 @@
1
- module Recurly
2
- module Verification
3
-
4
- def stringify_keys data
5
- Hash[data.map { |k, v| [k.to_s, v] }]
6
- end
7
-
8
- class PreEscapedString < String
9
- end
10
-
11
- def digest_data(data)
12
- if data.is_a? Array
13
- return nil if data.empty?
14
- PreEscapedString.new( '[%s]' % data.map{|v|digest_data(v)}.compact.join(',') )
15
- elsif data.is_a? Hash
16
- data = stringify_keys data
17
- digest_data data.sort.map {|k,v|
18
- prefix = (k =~ /\A\d+\Z/) ? '' : (k.to_s+':')
19
- (v=digest_data(v)).nil? ? nil : PreEscapedString.new('%s%s' % [prefix,v])
20
- }
21
- elsif data.is_a?(String) && !data.instance_of?(PreEscapedString)
22
- PreEscapedString.new( data.gsub(/([\[\]\,\:\\])/) { |c| '\\' + c } )
23
- else
24
- data
25
- end
26
- end
27
-
28
- def generate_signature(claim, args, timestamp=nil)
29
- raise Recurly::ConfigurationError.new("Recurly gem not configured. 'private_key' missing.") if Recurly.private_key.blank?
30
-
31
- timestamp ||= Time.now.to_i
32
- timestamp = timestamp.to_s
33
- input_data = [timestamp,claim,args]
34
- input_string = digest_data(input_data)
35
-
36
- digest_key = ::Digest::SHA1.digest(Recurly.private_key)
37
- sha1_hash = ::OpenSSL::Digest::Digest.new("sha1")
38
- signature = ::OpenSSL::HMAC.hexdigest(sha1_hash, digest_key, input_string.to_s)
39
- signature + '-' + timestamp
40
- end
41
-
42
- # Raises a Recurly::ForgedQueryString exception if the signature cannot be validated
43
- def verify_params!(claim, args)
44
- args = stringify_keys args
45
- signature = args.delete('signature') or raise Recurly::ForgedQueryString.new('Signature is missing')
46
- hmac, timestamp = signature.split('-')
47
- age = Time.now.to_i - timestamp.to_i
48
- raise Recurly::ForgedQueryString.new('Timestamp is too old or new') if age > 3600 || age < -3600
49
-
50
- if signature != generate_signature(claim, args, timestamp)
51
- raise Recurly::ForgedQueryString.new('Signature cannot be verified')
52
- end
53
- end
54
-
55
- def sign_billing_info_update(account_code)
56
- generate_signature('billinginfoupdate', {
57
- :account_code => account_code
58
- })
59
- end
60
-
61
- def sign_transaction(amount_in_cents, currency, account_code=nil)
62
- generate_signature('transactioncreate', {
63
- :account_code => account_code,
64
- :currency => currency,
65
- :amount_in_cents => amount_in_cents
66
- })
67
- end
68
-
69
- def verify_subscription!(params)
70
- verify_params! 'subscriptioncreated', params
71
- end
72
-
73
- def verify_transaction!(params)
74
- verify_params! 'transactioncreated', params
75
- end
76
-
77
- def verify_billing_info_update!(params)
78
- verify_params! 'billinginfoupdated', params
79
- end
80
-
81
- extend self
82
- end
83
- end
@@ -1,6 +0,0 @@
1
- ---
2
- username: api-test@litle.com
3
- password: 6499f1cd3ae14875beb91417d31e91b7
4
- private_key: 78753d36439c423aba60e581be828a2a
5
- subdomain: litle-test
6
- environment: :development
@@ -1,4 +0,0 @@
1
- ---
2
- api_key: asdf4jk31
3
- subdomain: site1
4
- private_key: asdfasdfasdf
@@ -1,7 +0,0 @@
1
- development:
2
- api_key: asdf4jk31
3
- subdomain: site1
4
-
5
- test:
6
- api_key: asdf4jk32
7
- subdomain: site2
@@ -1,286 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Recurly
4
- describe Account do
5
- timestamp = File.mtime(__FILE__).to_i
6
-
7
- describe "#new" do
8
- let(:attributes) { Factory.account_attributes("account-new-#{timestamp}") }
9
- before(:each) do
10
- @account = Account.new(attributes)
11
- end
12
-
13
- it "should be valid" do
14
- @account.should be_valid
15
- end
16
-
17
- it "should not be persisted" do
18
- @account.should_not be_persisted
19
- end
20
-
21
- it "should set the attributes correctly" do
22
- attributes.each do |key, val|
23
- @account.attributes[key].should == val
24
- end
25
- end
26
- end
27
-
28
- describe "#create" do
29
- context "with full data" do
30
- use_vcr_cassette "account/create/#{timestamp}"
31
-
32
- let(:attributes) { Factory.account_attributes("account-create-#{timestamp}") }
33
- before(:each) do
34
- @account = Account.create(attributes)
35
- end
36
-
37
- it "should be persisted" do
38
- @account.should be_persisted
39
- end
40
-
41
- it "should be valid" do
42
- @account.should be_valid
43
- end
44
-
45
- it "should set a created_at date from the server" do
46
- @account.created_at.should_not be_nil
47
- end
48
-
49
- it "should set a hosted_login_token from the server" do
50
- @account.hosted_login_token.should_not be_nil
51
- end
52
-
53
- it "should set the balance to 0" do
54
- @account.balance_in_cents.should == 0
55
- end
56
-
57
- it "should set the account status to active" do
58
- @account.state.should == "active"
59
- @account.closed?.should be_false
60
- end
61
- end
62
-
63
- context "with just account-code" do
64
- use_vcr_cassette "account/create-min/#{timestamp}"
65
-
66
- before(:each) do
67
- @account = Account.create(:account_code => "d00d-#{timestamp}")
68
- end
69
-
70
- it "should be valid" do
71
- @account.should be_valid
72
- end
73
-
74
- it "should set a created_at date from the server" do
75
- @account.created_at.should_not be_nil
76
- end
77
-
78
- end
79
- end
80
-
81
- describe "#find" do
82
- use_vcr_cassette "account/find/#{timestamp}"
83
- let(:orig){ Factory.create_account("account-get-#{timestamp}") }
84
-
85
- before(:each) do
86
- @account = Account.find(orig.account_code)
87
- end
88
-
89
- it "should return the account object" do
90
- @account.should_not be_nil
91
- end
92
-
93
- it "should be persisted" do
94
- @account.should be_persisted
95
- end
96
-
97
- describe "returned account" do
98
- it "should have a created_at date" do
99
- @account.created_at.should_not be_nil
100
- end
101
-
102
- it "should match the original account code" do
103
- @account.account_code.should == orig.account_code
104
- end
105
-
106
- it "should match the original account email" do
107
- @account.email.should == orig.email
108
- end
109
-
110
- it "should match the original first name" do
111
- @account.first_name.should == orig.first_name
112
- end
113
- end
114
-
115
- context "looking for a non-existant account" do
116
- it "should raise an ActiveResource::ResourceNotFound exception" do
117
- expect {
118
- Account.find('account-that-doesnt-exist')
119
- }.to raise_error ActiveResource::ResourceNotFound
120
- end
121
- end
122
- end
123
-
124
-
125
- # spec list queries for finding acocunts
126
- describe "#list" do
127
- use_vcr_cassette "account/list/#{timestamp}"
128
-
129
- before(:each) do
130
-
131
- # create new ones
132
- @accounts = []
133
- 8.times do |i|
134
- @accounts << Factory.create_account("account-list-num-#{i}-#{timestamp}")
135
- end
136
-
137
- # mark the 4 of them as paid
138
- @subscriptions = []
139
- @accounts[0, 4].each do |account|
140
- @subscriptions << Factory.create_subscription(account, :paid)
141
- end
142
- end
143
-
144
- it "should return a list of accounts with matching criteria" do
145
- Account.list(:all).total_entries.should >= 8
146
- Account.list(:active).total_entries.should >= 4
147
- Account.list(:free).total_entries.should >= 4
148
- end
149
-
150
- end
151
-
152
-
153
- describe "#update" do
154
- use_vcr_cassette "account/update/#{timestamp}"
155
-
156
- let(:orig){ Factory.create_account("account-update-#{timestamp}") }
157
-
158
- before(:each) do
159
- # update account data
160
- @account = Account.find(orig.account_code)
161
- @account.last_name = "Update Test"
162
- @account.company_name = "Recurly Ruby Gem -- Update"
163
- @account.save!
164
-
165
- # refetch account
166
- @account = Account.find(orig.account_code)
167
- end
168
-
169
- it "should not have updated the email address" do
170
- @account.email.should == orig.email
171
- end
172
-
173
- it "should have updated the last_name" do
174
- @account.last_name.should == "Update Test"
175
- end
176
-
177
- it "should have updated the company_name" do
178
- @account.company_name.should == "Recurly Ruby Gem -- Update"
179
- end
180
- end
181
-
182
- # EDITING ACCOUNT_CODE NOT YET SUPPORTED ON RECURLY API
183
- # describe "#update with account_code" do
184
- # use_vcr_cassette "account/update2/#{timestamp}"
185
- #
186
- # let(:orig){ Factory.create_account("account-update2-#{timestamp}") }
187
- #
188
- # let(:new_account_code){ "#{orig.account_code}-edited" }
189
- #
190
- # before(:each) do
191
- # # update account data
192
- # @account = Account.find(orig.account_code)
193
- # @account.account_code = new_account_code
194
- # @account.save!
195
- #
196
- # @account = Account.find(new_account_code)
197
- # end
198
- #
199
- # it "should update the account code" do
200
- # @account.account_code.should == new_account_code
201
- # end
202
- # end
203
-
204
- describe "#close_account" do
205
- use_vcr_cassette "account/close/#{timestamp}"
206
- let(:account){ Factory.create_account("account-close-#{timestamp}") }
207
-
208
- before(:each) do
209
- account.close_account
210
-
211
- # load a fresh account
212
- @account = Account.find(account.account_code)
213
- end
214
-
215
- it "should mark the account as closed" do
216
- @account.state.should == "closed"
217
- @account.closed?.should be_true
218
- end
219
- end
220
-
221
- describe "validations" do
222
- context "with blank data" do
223
- use_vcr_cassette "account/create-blank/#{timestamp}"
224
-
225
- before(:each) do
226
- @account = Account.create({:account_code => ""})
227
- end
228
-
229
- it "should not be valid" do
230
- @account.should_not be_valid
231
- end
232
-
233
- it "should require setting an account code" do
234
- @account.errors[:account_code].should include("can't be blank")
235
- @account.errors[:account_code].should include("is invalid")
236
- end
237
- end
238
-
239
- context "with duplicate data" do
240
- use_vcr_cassette "account/create-duplicate/#{timestamp}"
241
-
242
- before(:each) do
243
- Account.create({:account_code => "account-exists"})
244
- @account = Account.create({:account_code => "account-exists"})
245
- end
246
-
247
- it "should not be valid" do
248
- @account.should_not be_valid
249
- end
250
-
251
- it "should require setting an account code" do
252
- @account.errors[:account_code].should include("has already been taken")
253
- end
254
- end
255
- end
256
-
257
- describe "defaulting account's accept_language to Recurly.current_accept_language" do
258
-
259
- context "user is from france" do
260
- # wrap these example runs, setting current_accept_language properly
261
- around(:each) do |example|
262
- old_setting = Recurly.current_accept_language
263
- Recurly.current_accept_language = "fr"
264
- example.run
265
- Recurly.current_accept_language = old_setting
266
- end
267
-
268
- context "user creates an account" do
269
- use_vcr_cassette "account/accept-language-account/#{timestamp}"
270
- let(:attributes) { Factory.account_attributes("account1-french-#{timestamp}") }
271
-
272
- before(:each) do
273
- @account = Account.create(attributes)
274
- end
275
-
276
- it "should automaticaly set the accounts accept_language" do
277
- @account.attributes[:accept_language].should == "fr"
278
- end
279
- end
280
-
281
- end
282
-
283
- end
284
-
285
- end
286
- end
@@ -1,84 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Recurly
4
- describe "Subscription Addons" do
5
- # version accounts based on this current files modification dates
6
- timestamp = File.mtime(__FILE__).to_i
7
-
8
- describe "create a subscription with addons" do
9
- use_vcr_cassette "subscription/addons/create/#{timestamp}"
10
-
11
- let(:account){ Factory.create_account("subscription-addons-create-#{timestamp}") }
12
-
13
- before(:each) do
14
- Factory.create_subscription(account, :paid, :add_ons => [
15
- {
16
- :add_on_code => "special",
17
- :quantity => 1,
18
- :unit_amount => 10,
19
- }
20
- ])
21
- end
22
-
23
- it "should return the subscription addons" do
24
- subscription = Subscription.find(account.account_code)
25
- subscription.add_ons.count == 1
26
- end
27
- end
28
-
29
- describe "add an addon to a subscription" do
30
- use_vcr_cassette "subscription/addons/add/#{timestamp}"
31
-
32
- let(:account){ Factory.create_account("subscription-addons-add-#{timestamp}") }
33
-
34
- before(:each) do
35
- Factory.create_subscription(account, :paid, :add_ons => [
36
- {
37
- :add_on_code => "special",
38
- :quantity => 1,
39
- :unit_amount => 10,
40
- }
41
- ])
42
- end
43
-
44
- it "should allow adding a new addon" do
45
- subscription = Subscription.find(account.account_code)
46
- subscription.add_ons << {
47
- :add_on_code => "special2",
48
- :quantity => 2,
49
- :unit_amount => 500
50
- }
51
- subscription.change('now', :add_ons => subscription.add_ons)
52
-
53
- subscription = Subscription.find(account.account_code)
54
- subscription.add_ons.count == 2
55
- end
56
- end
57
-
58
- describe "remove an addon from a subscription" do
59
- use_vcr_cassette "subscription/addons/remove/#{timestamp}"
60
-
61
- let(:account){ Factory.create_account("subscription-addons-remove-#{timestamp}") }
62
-
63
- before(:each) do
64
- Factory.create_subscription(account, :paid, :add_ons => [
65
- {
66
- :add_on_code => "special",
67
- :quantity => 1,
68
- :unit_amount => 1000,
69
- }
70
- ])
71
- end
72
-
73
- it "should allow removing an addon" do
74
- subscription = Subscription.find(account.account_code)
75
- subscription.change('now', :add_ons => [])
76
-
77
- subscription = Subscription.find(account.account_code)
78
- subscription.add_ons.count == 0
79
- end
80
-
81
- end
82
-
83
- end
84
- end