saucy 0.15.2 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/CHANGELOG.md +3 -7
- data/Gemfile +1 -10
- data/Gemfile.lock +42 -3
- data/README.md +5 -0
- data/Rakefile +12 -3
- data/app/controllers/accounts_controller.rb +2 -1
- data/app/mailers/billing_mailer.rb +8 -0
- data/app/models/canceled_account.rb +12 -7
- data/app/views/accounts/_projects.html.erb +1 -1
- data/app/views/billing_mailer/cancelation_notification.text.erb +3 -0
- data/app/views/invitation_mailer/invitation.text.erb +1 -1
- data/app/views/invitations/show.html.erb +1 -1
- data/app/views/memberships/edit.html.erb +2 -2
- data/app/views/memberships/index.html.erb +1 -1
- data/app/views/projects/_form.html.erb +5 -5
- data/app/views/projects/edit.html.erb +2 -2
- data/app/views/projects/index.html.erb +3 -3
- data/app/views/projects/new.html.erb +1 -1
- data/app/views/shared/_project_dropdown.html.erb +3 -3
- data/config/routes.rb +2 -6
- data/cucumber.yml +1 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/admin_reporting.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/edit_profile.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/edit_project_permissions.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/edit_user_permissions.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/manage_account.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/manage_billing.feature +1 -1
- data/{lib/generators/saucy/features/templates/features → features/engine}/manage_plan.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/manage_projects.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/manage_users.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/new_account.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/project_dropdown.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/sign_up.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/sign_up_coupon.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/sign_up_paid.feature +0 -0
- data/{lib/generators/saucy/features/templates/features → features/engine}/trial_plans.feature +0 -0
- data/features/integration/run_features.feature +46 -0
- data/features/step_definitions/clearance_steps.rb +123 -0
- data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/account_steps.rb +0 -0
- data/features/step_definitions/engine/braintree_steps.rb +24 -0
- data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/country_steps.rb +0 -0
- data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/cron_steps.rb +3 -5
- data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/email_steps.rb +0 -0
- data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/factory_girl_steps.rb +0 -0
- data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/html_steps.rb +0 -0
- data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/plan_steps.rb +0 -0
- data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/project_steps.rb +0 -0
- data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/session_steps.rb +0 -0
- data/{lib/generators/saucy/features/templates/step_definitions → features/step_definitions/engine}/user_steps.rb +0 -0
- data/features/step_definitions/rails_steps.rb +26 -8
- data/features/step_definitions/saucy_steps.rb +5 -0
- data/features/step_definitions/web_steps.rb +253 -0
- data/features/support/engine/braintree.rb +5 -0
- data/features/support/env.rb +18 -0
- data/features/support/factory_girl.rb +2 -0
- data/features/support/paths.rb +68 -0
- data/features/support/rails.rb +4 -0
- data/features/support/selectors.rb +11 -0
- data/lib/generators/saucy/features/features_generator.rb +7 -3
- data/lib/saucy/account.rb +55 -57
- data/lib/saucy/account_authorization.rb +39 -42
- data/lib/saucy/plan.rb +14 -16
- data/lib/saucy/project.rb +42 -44
- data/lib/saucy/projects_controller.rb +53 -55
- data/lib/saucy/subscription.rb +189 -191
- data/lib/saucy/user.rb +5 -7
- data/lib/saucy/version.rb +1 -1
- data/saucy.gemspec +21 -5
- data/spec/controllers/accounts_controller_spec.rb +2 -1
- data/spec/controllers/projects_controller_spec.rb +1 -1
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +9 -0
- data/spec/dummy/app/assets/stylesheets/application.css +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/homes_controller.rb +2 -0
- data/spec/dummy/app/controllers/projects_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/account.rb +3 -0
- data/spec/dummy/app/models/plan.rb +3 -0
- data/spec/dummy/app/models/project.rb +3 -0
- data/spec/dummy/app/models/user.rb +4 -0
- data/spec/dummy/app/views/homes/show.html.erb +1 -0
- data/spec/dummy/app/views/layouts/application.html.erb +24 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +48 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +30 -0
- data/spec/dummy/config/environments/production.rb +60 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/clearance.rb +3 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +59 -0
- data/spec/dummy/db/migrate/20120201000751_create_diesel_clearance_users.rb +19 -0
- data/spec/dummy/db/migrate/20120201001546_create_saucy_tables.rb +122 -0
- data/spec/dummy/db/migrate/20120201001548_create_canceled_accounts.rb +14 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/mailers/billing_mailer_spec.rb +12 -2
- data/spec/models/canceled_account_spec.rb +8 -6
- data/spec/models/subscription_spec.rb +47 -53
- data/spec/spec_helper.rb +8 -11
- data/spec/support/braintree.rb +2 -4
- data/spec/support/factories.rb +1 -0
- metadata +447 -125
- data/db/migrate/20120206155222_add_subscription_token_to_canceled_accounts.rb +0 -5
- data/features/run_features.feature +0 -84
- data/lib/generators/saucy/features/templates/step_definitions/braintree_steps.rb +0 -25
- data/lib/generators/saucy/features/templates/support/braintree.rb +0 -5
- data/lib/generators/saucy/specs/specs_generator.rb +0 -20
- data/lib/generators/saucy/specs/templates/support/braintree.rb +0 -5
- data/lib/saucy/fake_braintree.rb +0 -134
- data/lib/saucy/routing_extensions.rb +0 -116
- data/spec/dummy/db/migrate/20120206155222_add_subscription_token_to_canceled_accounts.rb +0 -5
- data/spec/environment.rb +0 -98
- data/spec/route_extensions_spec.rb +0 -51
- data/spec/scaffold/config/database.yml +0 -6
- data/spec/scaffold/config/routes.rb +0 -5
- data/spec/scaffold/views/layouts/application.html.erb +0 -1
@@ -1,84 +0,0 @@
|
|
1
|
-
@disable-bundler @puts @announce
|
2
|
-
Feature: generate a saucy application and run rake
|
3
|
-
|
4
|
-
Background:
|
5
|
-
When I successfully run `bundle exec rails new testapp`
|
6
|
-
And I cd to "testapp"
|
7
|
-
And I copy the locked Gemfile from this project
|
8
|
-
And I append to "Gemfile" with:
|
9
|
-
"""
|
10
|
-
gem "clearance", "~> 0.14.0"
|
11
|
-
gem "cucumber-rails"
|
12
|
-
gem "selenium-webdriver", "~> 2.16.0"
|
13
|
-
gem "capybara"
|
14
|
-
gem "factory_girl_rails"
|
15
|
-
gem "dynamic_form"
|
16
|
-
gem "database_cleaner"
|
17
|
-
gem "formtastic", "~> 1.2.4"
|
18
|
-
gem "rspec-rails"
|
19
|
-
gem "bourne"
|
20
|
-
gem "shoulda-matchers"
|
21
|
-
gem "launchy"
|
22
|
-
gem "timecop"
|
23
|
-
gem "jquery-rails"
|
24
|
-
gem "minitest", "~> 2.6.1", :platforms => :ruby_19
|
25
|
-
"""
|
26
|
-
When I add the "saucy" gem from this project as a dependency
|
27
|
-
And I successfully run `bundle install`
|
28
|
-
And I bootstrap the application for clearance
|
29
|
-
And I bootstrap the application for saucy
|
30
|
-
|
31
|
-
Scenario: generate a saucy application and run rake
|
32
|
-
When I successfully run `rails generate saucy:install`
|
33
|
-
And I successfully run `rails generate saucy:specs`
|
34
|
-
And I successfully run `rails generate saucy:features`
|
35
|
-
And I successfully run `bundle exec rake db:migrate`
|
36
|
-
And I run `bundle exec rake`
|
37
|
-
Then it should pass with:
|
38
|
-
"""
|
39
|
-
passed
|
40
|
-
"""
|
41
|
-
Then the output should not contain "failed"
|
42
|
-
And the output should not contain "Could not find generator"
|
43
|
-
|
44
|
-
Scenario: A new saucy app with custom views
|
45
|
-
When I successfully run `rails generate saucy:install`
|
46
|
-
And I successfully run `rails generate saucy:specs`
|
47
|
-
And I successfully run `rails generate saucy:features`
|
48
|
-
And I successfully run `rails generate saucy:views`
|
49
|
-
And I successfully run `bundle exec rake db:migrate`
|
50
|
-
And I give a more detailed new account message
|
51
|
-
And I run `bundle exec rake`
|
52
|
-
Then it should pass with:
|
53
|
-
"""
|
54
|
-
passed
|
55
|
-
"""
|
56
|
-
Then the output should not contain "failed"
|
57
|
-
And the output should not contain "Could not find generator"
|
58
|
-
|
59
|
-
Scenario: A new saucy app with custom layouts
|
60
|
-
When I successfully run `rails generate saucy:install`
|
61
|
-
And I successfully run `rails generate saucy:specs`
|
62
|
-
And I successfully run `rails generate saucy:features`
|
63
|
-
And I successfully run `bundle exec rake db:migrate`
|
64
|
-
And I add a custom layout to the accounts index
|
65
|
-
And I run `bundle exec rake`
|
66
|
-
Then it should pass with:
|
67
|
-
"""
|
68
|
-
passed
|
69
|
-
"""
|
70
|
-
Then the output should not contain "failed"
|
71
|
-
And the output should not contain "Could not find generator"
|
72
|
-
|
73
|
-
Scenario: run specs
|
74
|
-
When I successfully run `rails generate saucy:install`
|
75
|
-
And I successfully run `rails generate saucy:specs`
|
76
|
-
And I successfully run `rails generate saucy:features`
|
77
|
-
And I successfully run `bundle exec rake db:migrate`
|
78
|
-
And I copy the specs for this project
|
79
|
-
And I run `bundle exec rake spec`
|
80
|
-
Then it should pass with:
|
81
|
-
"""
|
82
|
-
0 failures
|
83
|
-
"""
|
84
|
-
Then at least one example should have run
|
@@ -1,25 +0,0 @@
|
|
1
|
-
Given /^that the credit card "([^"]*)" is invalid$/ do |number|
|
2
|
-
FakeBraintree.failures[number] = { "message" => "Credit card number is invalid.", "errors" => { "customer" => { "errors" => [], "credit-card" => { "errors" => [{ "message" => "Credit card number is invalid.", "code" => 81715, "attribute" => :number }] }}}}
|
3
|
-
end
|
4
|
-
|
5
|
-
Given /^that the credit card "([^"]*)" should not be honored$/ do |number|
|
6
|
-
FakeBraintree.failures[number] = { "message" => "Do Not Honor", "code" => "2000", "status" => "processor_declined" }
|
7
|
-
end
|
8
|
-
|
9
|
-
Given /^the "([^"]*)" account is past due$/ do |account_name|
|
10
|
-
account = Account.find_by_name!(account_name)
|
11
|
-
account.update_attribute(:subscription_status, Braintree::Subscription::Status::PastDue)
|
12
|
-
end
|
13
|
-
|
14
|
-
Given /^the following transaction exist for the "([^"]*)" account:$/ do |account_name, table|
|
15
|
-
account = Account.find_by_name!(account_name)
|
16
|
-
subscription = FakeBraintree.subscriptions[account.subscription_token]
|
17
|
-
subscription["transactions"] = []
|
18
|
-
table.hashes.each do |transaction|
|
19
|
-
FakeBraintree.transaction = { :status => transaction["status"],
|
20
|
-
:amount => transaction["amount"],
|
21
|
-
:created_at => DateTime.parse(transaction["created_at"]),
|
22
|
-
:subscription_id => account.subscription_token }
|
23
|
-
subscription["transactions"] << FakeBraintree.generated_transaction
|
24
|
-
end
|
25
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'generators/saucy/base'
|
2
|
-
|
3
|
-
module Saucy
|
4
|
-
module Generators
|
5
|
-
class SpecsGenerator < Base
|
6
|
-
|
7
|
-
desc <<DESC
|
8
|
-
Description:
|
9
|
-
Copy saucy cucumber spec support files to your application.
|
10
|
-
DESC
|
11
|
-
|
12
|
-
def copy_spec_files
|
13
|
-
directory "support", "spec/support/saucy"
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
|
data/lib/saucy/fake_braintree.rb
DELETED
@@ -1,134 +0,0 @@
|
|
1
|
-
require 'braintree'
|
2
|
-
|
3
|
-
Braintree::Configuration.environment = :production
|
4
|
-
Braintree::Configuration.merchant_id = "xxx"
|
5
|
-
Braintree::Configuration.public_key = "xxx"
|
6
|
-
Braintree::Configuration.private_key = "xxx"
|
7
|
-
|
8
|
-
require 'digest/md5'
|
9
|
-
require 'sham_rack'
|
10
|
-
|
11
|
-
class FakeBraintree
|
12
|
-
cattr_accessor :customers, :subscriptions, :failures, :transaction
|
13
|
-
@@customers = {}
|
14
|
-
@@subscriptions = {}
|
15
|
-
@@failures = {}
|
16
|
-
@@transaction = {}
|
17
|
-
|
18
|
-
def self.clear!
|
19
|
-
@@customers = {}
|
20
|
-
@@subscriptions = {}
|
21
|
-
@@failures = {}
|
22
|
-
@@transaction = {}
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.failure?(card_number)
|
26
|
-
self.failures.include?(card_number)
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.failure_response(card_number)
|
30
|
-
failure = self.failures[card_number]
|
31
|
-
failure["errors"] ||= { "errors" => [] }
|
32
|
-
{ "message" => failure["message"], "verification" => { "status" => failure["status"], "processor_response_text" => failure["message"], "processor-response-code" => failure["code"], "gateway_rejection_reason" => "cvv", "cvv_response_code" => failure["code"] }, "errors" => failure["errors"], "params" => {}}
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.generated_transaction
|
36
|
-
{"status_history"=>[{"timestamp"=>Time.now, "amount"=>FakeBraintree.transaction[:amount], "transaction_source"=>"CP", "user"=>"copycopter", "status"=>"authorized"}, {"timestamp"=>Time.now, "amount"=>FakeBraintree.transaction[:amount], "transaction_source"=>"CP", "user"=>"copycopter", "status"=>FakeBraintree.transaction[:status]}], "created_at"=>(FakeBraintree.transaction[:created_at] || Time.now), "currency_iso_code"=>"USD", "settlement_batch_id"=>nil, "processor_authorization_code"=>"ZKB4VJ", "avs_postal_code_response_code"=>"I", "order_id"=>nil, "updated_at"=>Time.now, "refunded_transaction_id"=>nil, "amount"=>FakeBraintree.transaction[:amount], "credit_card"=>{"last_4"=>"1111", "card_type"=>"Visa", "token"=>"8yq7", "customer_location"=>"US", "expiration_year"=>"2013", "expiration_month"=>"02", "bin"=>"411111", "cardholder_name"=>"Chad Lee Pytel"}, "refund_id"=>nil, "add_ons"=>[], "shipping"=>{"region"=>nil, "company"=>nil, "country_name"=>nil, "extended_address"=>nil, "postal_code"=>nil, "id"=>nil, "street_address"=>nil, "country_code_numeric"=>nil, "last_name"=>nil, "locality"=>nil, "country_code_alpha2"=>nil, "country_code_alpha3"=>nil, "first_name"=>nil}, "id"=>"49sbx6", "merchant_account_id"=>"Thoughtbot", "type"=>"sale", "cvv_response_code"=>"I", "subscription_id"=>FakeBraintree.transaction[:subscription_id], "custom_fields"=>"\n ", "discounts"=>[], "billing"=>{"region"=>nil, "company"=>nil, "country_name"=>nil, "extended_address"=>nil, "postal_code"=>nil, "id"=>nil, "street_address"=>nil, "country_code_numeric"=>nil, "last_name"=>nil, "locality"=>nil, "country_code_alpha2"=>nil, "country_code_alpha3"=>nil, "first_name"=>nil}, "processor_response_code"=>"1000", "refund_ids"=>[], "customer"=>{"company"=>nil, "id"=>"108427", "last_name"=>nil, "fax"=>nil, "phone"=>nil, "website"=>nil, "first_name"=>nil, "email"=>"cpytel@thoughtbot.com"}, "avs_error_response_code"=>nil, "processor_response_text"=>"Approved", "avs_street_address_response_code"=>"I", "status"=>FakeBraintree.transaction[:status], "gateway_rejection_reason"=>nil}
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
ShamRack.at("www.braintreegateway.com", 443).sinatra do
|
41
|
-
set :show_exceptions, false
|
42
|
-
set :dump_errors, true
|
43
|
-
set :raise_errors, true
|
44
|
-
disable :logging
|
45
|
-
|
46
|
-
post "/merchants/:merchant_id/customers" do
|
47
|
-
customer = Hash.from_xml(request.body).delete("customer")
|
48
|
-
if !FakeBraintree.failure?(customer["credit_card"]["number"])
|
49
|
-
customer["id"] ||= Digest::MD5.hexdigest("#{params[:merchant_id]}#{Time.now.to_f}")
|
50
|
-
customer["merchant-id"] = params[:merchant_id]
|
51
|
-
if customer["credit_card"] && customer["credit_card"].is_a?(Hash)
|
52
|
-
customer["credit_card"].delete("__content__")
|
53
|
-
if !customer["credit_card"].empty?
|
54
|
-
customer["credit_card"]["last_4"] = customer["credit_card"].delete("number")[-4..-1]
|
55
|
-
customer["credit_card"]["token"] = Digest::MD5.hexdigest("#{customer['merchant_id']}#{customer['id']}#{Time.now.to_f}")
|
56
|
-
credit_card = customer.delete("credit_card")
|
57
|
-
customer["credit_cards"] = [credit_card]
|
58
|
-
end
|
59
|
-
end
|
60
|
-
FakeBraintree.customers[customer["id"]] = customer
|
61
|
-
[201, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress(customer.to_xml(:root => 'customer'))]
|
62
|
-
else
|
63
|
-
[422, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress(FakeBraintree.failure_response(customer["credit_card"]["number"]).to_xml(:root => 'api_error_response'))]
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
get "/merchants/:merchant_id/customers/:id" do
|
68
|
-
customer = FakeBraintree.customers[params[:id]]
|
69
|
-
[200, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress(customer.to_xml(:root => 'customer'))]
|
70
|
-
end
|
71
|
-
|
72
|
-
put "/merchants/:merchant_id/customers/:id" do
|
73
|
-
customer = Hash.from_xml(request.body).delete("customer")
|
74
|
-
if !FakeBraintree.failure?(customer["credit_card"]["number"])
|
75
|
-
customer["id"] = params[:id]
|
76
|
-
customer["merchant-id"] = params[:merchant_id]
|
77
|
-
if customer["credit_card"] && customer["credit_card"].is_a?(Hash)
|
78
|
-
customer["credit_card"].delete("__content__")
|
79
|
-
if !customer["credit_card"].empty?
|
80
|
-
customer["credit_card"]["last_4"] = customer["credit_card"].delete("number")[-4..-1]
|
81
|
-
customer["credit_card"]["token"] = Digest::MD5.hexdigest("#{customer['merchant_id']}#{customer['id']}#{Time.now.to_f}")
|
82
|
-
credit_card = customer.delete("credit_card")
|
83
|
-
customer["credit_cards"] = [credit_card]
|
84
|
-
end
|
85
|
-
end
|
86
|
-
FakeBraintree.customers[params["id"]] = customer
|
87
|
-
[200, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress(customer.to_xml(:root => 'customer'))]
|
88
|
-
else
|
89
|
-
[422, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress(FakeBraintree.failure_response(customer["credit_card"]["number"]).to_xml(:root => 'api_error_response'))]
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
delete "/merchants/:merchant_id/customers/:id" do
|
94
|
-
FakeBraintree.customers[params["id"]] = nil
|
95
|
-
[200, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress("")]
|
96
|
-
end
|
97
|
-
|
98
|
-
post "/merchants/:merchant_id/subscriptions" do
|
99
|
-
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<subscription>\n <plan-id type=\"integer\">2</plan-id>\n <payment-method-token>b22x</payment-method-token>\n</subscription>\n"
|
100
|
-
subscription = Hash.from_xml(request.body).delete("subscription")
|
101
|
-
subscription["id"] ||= Digest::MD5.hexdigest("#{subscription["payment_method_token"]}#{Time.now.to_f}")
|
102
|
-
subscription["transactions"] = []
|
103
|
-
subscription["add_ons"] = []
|
104
|
-
subscription["discounts"] = []
|
105
|
-
subscription["next_billing_date"] = 1.month.from_now.to_s(:braintree_date)
|
106
|
-
subscription["status"] = Braintree::Subscription::Status::Active
|
107
|
-
FakeBraintree.subscriptions[subscription["id"]] = subscription
|
108
|
-
[201, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress(subscription.to_xml(:root => 'subscription'))]
|
109
|
-
end
|
110
|
-
|
111
|
-
get "/merchants/:merchant_id/subscriptions/:id" do
|
112
|
-
subscription = FakeBraintree.subscriptions[params[:id]]
|
113
|
-
[200, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress(subscription.to_xml(:root => 'subscription'))]
|
114
|
-
end
|
115
|
-
|
116
|
-
put "/merchants/:merchant_id/subscriptions/:id" do
|
117
|
-
subscription = Hash.from_xml(request.body).delete("subscription")
|
118
|
-
subscription["transactions"] = []
|
119
|
-
subscription["add_ons"] = []
|
120
|
-
subscription["discounts"] = []
|
121
|
-
FakeBraintree.subscriptions[params["id"]] = subscription
|
122
|
-
[200, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress(subscription.to_xml(:root => 'subscription'))]
|
123
|
-
end
|
124
|
-
|
125
|
-
post "/merchants/:merchant_id/transactions/advanced_search_ids" do
|
126
|
-
# "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<search>\n <created-at>\n <min type=\"datetime\">2011-01-10T14:14:26Z</min>\n </created-at>\n</search>\n"
|
127
|
-
[200, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress("<search-results>\n <page-size type=\"integer\">50</page-size>\n <ids type=\"array\">\n <item>49sbx6</item>\n </ids>\n</search-results>\n")]
|
128
|
-
end
|
129
|
-
|
130
|
-
post "/merchants/:merchant_id/transactions/advanced_search" do
|
131
|
-
# "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<search>\n <ids type=\"array\">\n <item>49sbx6</item>\n </ids>\n <created-at>\n <min type=\"datetime\">2011-01-10T14:14:26Z</min>\n </created-at>\n</search>\n"
|
132
|
-
[200, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress(FakeBraintree.generated_transaction.to_xml)]
|
133
|
-
end
|
134
|
-
end
|
@@ -1,116 +0,0 @@
|
|
1
|
-
# This set of hacks extends Rails routing so that we can define pretty, unique,
|
2
|
-
# urls for account resources without having to specify every nested resource
|
3
|
-
# every time we generate a url.
|
4
|
-
#
|
5
|
-
# For example, you can generate /accounts/thoughtbot/projects/hoptoad from
|
6
|
-
# project_path(@project), because the account can be inferred from the project.
|
7
|
-
module Saucy
|
8
|
-
module MapperExtensions
|
9
|
-
def through(parent, &block)
|
10
|
-
(@through_scope ||= []) << parent
|
11
|
-
resources(parent, :only => [], &block)
|
12
|
-
@through_scope.pop
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
class ThroughAlias
|
18
|
-
attr_reader :route, :through
|
19
|
-
|
20
|
-
def initialize(route, through)
|
21
|
-
@route = route
|
22
|
-
@through = through
|
23
|
-
end
|
24
|
-
|
25
|
-
def to_method(kind)
|
26
|
-
return <<-RUBY
|
27
|
-
def #{alias_name}_#{kind}(#{arguments.last}, options = {})
|
28
|
-
#{route_name}_#{kind}(#{arguments.join(', ')}, options)
|
29
|
-
end
|
30
|
-
RUBY
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def alias_name
|
36
|
-
@alias_name ||= through.inject(route_name) do |name, through|
|
37
|
-
prefix = "#{through.to_s.singularize}_"
|
38
|
-
name.sub(/^(new_|edit_|)#{Regexp.escape(prefix)}/, '\1')
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def arguments
|
43
|
-
@arguments ||= build_arguments
|
44
|
-
end
|
45
|
-
|
46
|
-
def build_arguments
|
47
|
-
other_segments = segments.dup
|
48
|
-
first_segment = other_segments.shift
|
49
|
-
other_segments.inject([first_segment]) { |result, member|
|
50
|
-
result << "#{result.last}.#{member}"
|
51
|
-
}.reverse
|
52
|
-
end
|
53
|
-
|
54
|
-
def segments
|
55
|
-
parent_segments = through.map { |parent| parent.to_s.singularize }.reverse
|
56
|
-
if include_self?
|
57
|
-
[alias_name] + parent_segments
|
58
|
-
else
|
59
|
-
parent_segments
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def route_name
|
64
|
-
route.name
|
65
|
-
end
|
66
|
-
|
67
|
-
def include_self?
|
68
|
-
route.segment_keys.include?(:id)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
ActionDispatch::Routing::Mapper.class_eval do
|
74
|
-
include Saucy::MapperExtensions
|
75
|
-
end
|
76
|
-
|
77
|
-
ActionDispatch::Routing::Mapper::Base.class_eval do
|
78
|
-
def match_with_through(path, options=nil)
|
79
|
-
match_without_through(path, options)
|
80
|
-
if @through_scope.present?
|
81
|
-
route = @set.routes.last
|
82
|
-
@set.named_routes.add_through_alias(route, @through_scope) if route.name
|
83
|
-
end
|
84
|
-
self
|
85
|
-
end
|
86
|
-
|
87
|
-
alias_method_chain :match, :through
|
88
|
-
end
|
89
|
-
|
90
|
-
ActionDispatch::Routing::RouteSet::NamedRouteCollection.class_eval do
|
91
|
-
attr_reader :through_aliases
|
92
|
-
|
93
|
-
def clear_with_through_aliases!
|
94
|
-
clear_without_through_aliases!
|
95
|
-
@through_aliases = []
|
96
|
-
end
|
97
|
-
alias_method_chain :clear!, :through_aliases
|
98
|
-
|
99
|
-
def reset_with_through_aliases!
|
100
|
-
old_through_aliases = through_aliases.dup
|
101
|
-
reset_without_through_aliases!
|
102
|
-
old_through_aliases.each do |through_alias|
|
103
|
-
add_through_alias through_alias.route, through_alias.through
|
104
|
-
end
|
105
|
-
end
|
106
|
-
alias_method_chain :reset!, :through_aliases
|
107
|
-
|
108
|
-
def add_through_alias(route, through)
|
109
|
-
@through_aliases ||= []
|
110
|
-
through_alias = Saucy::ThroughAlias.new(route, through)
|
111
|
-
@through_aliases << through_alias
|
112
|
-
@module.module_eval through_alias.to_method('path')
|
113
|
-
@module.module_eval through_alias.to_method('url')
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
data/spec/environment.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
PROJECT_ROOT = File.expand_path("../..", __FILE__)
|
2
|
-
$LOAD_PATH << File.join(PROJECT_ROOT, "lib")
|
3
|
-
|
4
|
-
require 'rails/all'
|
5
|
-
require 'saucy'
|
6
|
-
require 'clearance'
|
7
|
-
require 'factory_girl'
|
8
|
-
require 'bourne'
|
9
|
-
|
10
|
-
FileUtils.rm_f(File.join(PROJECT_ROOT, 'tmp', 'test.sqlite3'))
|
11
|
-
|
12
|
-
Clearance.configure do |config|
|
13
|
-
end
|
14
|
-
|
15
|
-
class ApplicationController < ActionController::Base
|
16
|
-
include Clearance::Authentication
|
17
|
-
include Saucy::AccountAuthorization
|
18
|
-
end
|
19
|
-
|
20
|
-
class ProjectsController < ApplicationController
|
21
|
-
include Saucy::ProjectsController
|
22
|
-
end
|
23
|
-
|
24
|
-
class User < ActiveRecord::Base
|
25
|
-
include Clearance::User
|
26
|
-
include Saucy::User
|
27
|
-
end
|
28
|
-
|
29
|
-
class Plan < ActiveRecord::Base
|
30
|
-
include Saucy::Plan
|
31
|
-
end
|
32
|
-
|
33
|
-
module Testapp
|
34
|
-
class Application < Rails::Application
|
35
|
-
config.action_mailer.default_url_options = { :host => 'localhost' }
|
36
|
-
config.encoding = "utf-8"
|
37
|
-
config.paths['config/database'] = "spec/scaffold/config/database.yml"
|
38
|
-
config.paths['app/models'] << "lib/generators/saucy/install/templates/models"
|
39
|
-
config.paths['config/routes'] << "spec/scaffold/config/routes.rb"
|
40
|
-
config.paths['app/views'] << "spec/scaffold/views"
|
41
|
-
config.paths['log'] = "tmp/log"
|
42
|
-
config.cache_classes = true
|
43
|
-
config.whiny_nils = true
|
44
|
-
config.consider_all_requests_local = true
|
45
|
-
config.action_controller.perform_caching = false
|
46
|
-
config.action_dispatch.show_exceptions = false
|
47
|
-
config.action_controller.allow_forgery_protection = false
|
48
|
-
config.action_mailer.delivery_method = :test
|
49
|
-
config.active_support.deprecation = :stderr
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
Testapp::Application.initialize!
|
54
|
-
ActionController::Base.send :include, Rails.application.routes.url_helpers
|
55
|
-
|
56
|
-
require "./lib/generators/saucy/features/templates/factories"
|
57
|
-
require "./lib/generators/saucy/install/templates/create_saucy_tables"
|
58
|
-
#Dir["./db/migrate/*.rb"].each {|file| require file }
|
59
|
-
|
60
|
-
class ClearanceCreateUsers < ActiveRecord::Migration
|
61
|
-
def self.up
|
62
|
-
create_table(:users) do |t|
|
63
|
-
t.string :email
|
64
|
-
t.string :encrypted_password, :limit => 128
|
65
|
-
t.string :salt, :limit => 128
|
66
|
-
t.string :confirmation_token, :limit => 128
|
67
|
-
t.string :remember_token, :limit => 128
|
68
|
-
t.boolean :email_confirmed, :default => false, :null => false
|
69
|
-
t.timestamps
|
70
|
-
end
|
71
|
-
|
72
|
-
add_index :users, :email
|
73
|
-
add_index :users, :remember_token
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
class ClearanceMailer
|
78
|
-
def self.change_password(user)
|
79
|
-
new
|
80
|
-
end
|
81
|
-
|
82
|
-
def self.confirmation(user)
|
83
|
-
new
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.deliver_change_password(user)
|
87
|
-
end
|
88
|
-
|
89
|
-
def self.deliver_confirmation(user)
|
90
|
-
end
|
91
|
-
|
92
|
-
def deliver
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
ClearanceCreateUsers.suppress_messages { ClearanceCreateUsers.migrate(:up) }
|
97
|
-
CreateSaucyTables.suppress_messages { CreateSaucyTables.migrate(:up) }
|
98
|
-
ActiveRecord::Migrator.up(ActiveRecord::Migrator.migrations_paths)
|