From 85113ca0954d076ad0e2e8514be2968d34eb3e7b Mon Sep 17 00:00:00 2001 From: Azul Date: Wed, 23 Mar 2016 21:26:29 +0100 Subject: upgrade: use recent gems - broken We can move to rails 4.2 with client_side_validations 4.2, simple_form 3.2 and bootstrap 3 Now we only need to migrate to these new dependencies. ;) --- Gemfile | 35 ++---- Gemfile.lock | 359 +++++++++++++++++++++++++++++++++-------------------------- Gemfile.orig | 119 ++++++++++++++++++++ 3 files changed, 330 insertions(+), 183 deletions(-) create mode 100644 Gemfile.orig diff --git a/Gemfile b/Gemfile index a38d1e9..5b5a33b 100644 --- a/Gemfile +++ b/Gemfile @@ -4,12 +4,12 @@ require File.expand_path('../lib/gemfile_tools.rb', __FILE__) ## CORE # rake 11.x throws lots of warnings about rails 3.2 code -gem "rake", "~> 10.4" -gem "rails", "~> 3.2.21" +gem "rake" +gem "rails", "~> 4.2.6" gem "couchrest", "~> 1.1.3" gem "couchrest_model", "~> 2.0.0" if ARGV.grep(/assets:precompile/).empty? - gem "couchrest_session_store", "= 0.3.1" + gem "couchrest_session_store", "~> 0.4.1" end ## AUTHENTICATION @@ -30,8 +30,7 @@ gem 'rails-i18n' # locale files for built-in validation messages and times gem 'common_languages', :path => 'vendor/gems/common_languages' ## VIEWS -gem 'kaminari', "0.13.0" # for pagination. trying 0.13.0 as there seem to be - # issues with 0.14.0 when using couchrest +gem 'kaminari' gem 'rdiscount' # for rendering .md templates ## ASSETS @@ -39,19 +38,13 @@ gem "jquery-rails" gem "simple_form" gem 'client_side_validations' gem 'client_side_validations-simple_form' -gem "haml-rails", "= 0.4.0" # The last version of haml-rails to support Rails 3. -gem "bootstrap-sass", "= 2.3.2.2" # The last 2.x version. Bootstrap-sass versions - # tracks the version of Bootstrap. We currently require - # Bootstrap v2 because client side validations is incompatible - # with Bootstrap v3. When upgrading to Rails 4, see - # https://github.com/twbs/bootstrap-sass -gem "sass-rails", "~> 3.2.5" # Only version supported by bootstrap-sass 2.3.2.2 +gem "haml-rails" +gem "bootstrap-sass" +gem "sass-rails" gem 'quiet_assets' # stops logging all the asset requests group :production do - gem "uglifier", "~> 1.2.7" # javascript compression https://github.com/lautis/uglifier - # this must not be included in development mode, or js - # will get included twice. - gem 'therubyracer', "~> 0.12.2", :platforms => :ruby + gem "uglifier" + gem 'therubyracer', :platforms => :ruby # ^^ See https://github.com/sstephenson/execjs#readme # for list of supported runtimes. end @@ -68,7 +61,7 @@ group :test do gem 'phantomjs-binaries' # binaries specific to the os # moching and stubbing - gem 'mocha', '~> 0.13.0', :require => false + gem 'mocha', :require => false gem 'minitest-stub-const' # why? # generating test data @@ -93,17 +86,13 @@ group :production do end group :development do - gem "better_errors", '1.1.0' + gem "better_errors" gem "binding_of_caller" end group :test, :debug do # bundler on jessie doesn't support `:platforms => :ruby_21` - if RUBY_VERSION < "2.0" - gem 'debugger' - else - gem 'byebug' - end + gem 'byebug' end ## diff --git a/Gemfile.lock b/Gemfile.lock index af414c1..3344b5c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,13 +1,13 @@ PATH remote: engines/billing specs: - leap_web_billing (0.6.0) + leap_web_billing (0.8.0) braintree PATH remote: engines/support specs: - leap_web_help (0.6.0) + leap_web_help (0.8.0) PATH remote: vendor/gems/certificate_authority @@ -26,58 +26,75 @@ GEM remote: https://rubygems.org/ specs: SyslogLogger (2.0) - actionmailer (3.2.22.2) - actionpack (= 3.2.22.2) - mail (~> 2.5.4) - actionpack (3.2.22.2) - activemodel (= 3.2.22.2) - activesupport (= 3.2.22.2) - builder (~> 3.0.0) + actionmailer (4.2.6) + actionpack (= 4.2.6) + actionview (= 4.2.6) + activejob (= 4.2.6) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 1.0, >= 1.0.5) + actionpack (4.2.6) + actionview (= 4.2.6) + activesupport (= 4.2.6) + rack (~> 1.6) + rack-test (~> 0.6.2) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (4.2.6) + activesupport (= 4.2.6) + builder (~> 3.1) erubis (~> 2.7.0) - journey (~> 1.0.4) - rack (~> 1.4.5) - rack-cache (~> 1.2) - rack-test (~> 0.6.1) - sprockets (~> 2.2.1) - activemodel (3.2.22.2) - activesupport (= 3.2.22.2) - builder (~> 3.0.0) - activerecord (3.2.22.2) - activemodel (= 3.2.22.2) - activesupport (= 3.2.22.2) - arel (~> 3.0.2) - tzinfo (~> 0.3.29) - activeresource (3.2.22.2) - activemodel (= 3.2.22.2) - activesupport (= 3.2.22.2) - activesupport (3.2.22.2) - i18n (~> 0.6, >= 0.6.4) - multi_json (~> 1.0) - addressable (2.3.6) - arel (3.0.3) - better_errors (1.1.0) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + activejob (4.2.6) + activesupport (= 4.2.6) + globalid (>= 0.3.0) + activemodel (4.2.6) + activesupport (= 4.2.6) + builder (~> 3.1) + activerecord (4.2.6) + activemodel (= 4.2.6) + activesupport (= 4.2.6) + arel (~> 6.0) + activesupport (4.2.6) + i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + addressable (2.4.0) + arel (6.0.3) + autoprefixer-rails (6.3.6) + execjs + better_errors (2.1.1) coderay (>= 1.0.0) erubis (>= 2.6.6) + rack (>= 0.9.0) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) - bootstrap-sass (2.3.2.2) - sass (~> 3.2) - braintree (2.48.1) + bootstrap-sass (3.3.6) + autoprefixer-rails (>= 5.2.1) + sass (>= 3.3.4) + braintree (2.60.0) builder (>= 2.0.0) - builder (3.0.4) - byebug (8.2.1) - capybara (2.4.4) + builder (3.2.2) + byebug (8.2.5) + capybara (2.7.1) + addressable mime-types (>= 1.16) nokogiri (>= 1.3.3) rack (>= 1.0.0) rack-test (>= 0.5.4) xpath (~> 2.0) - client_side_validations (3.2.6) - client_side_validations-simple_form (2.1.0) - client_side_validations (~> 3.2.5) - simple_form (~> 2.1.0) + client_side_validations (4.2.3) + jquery-rails (>= 3.1.2, < 5.0.0) + js_regex (~> 1.0, >= 1.0.9) + rails (>= 4.0.0, < 4.3.0) + client_side_validations-simple_form (3.2.3) + client_side_validations (~> 4.2.3) + simple_form (~> 3.2) cliver (0.3.2) - coderay (1.1.0) + coderay (1.1.1) + concurrent-ruby (1.0.1) couchrest (1.1.3) mime-types (~> 1.15) multi_json (~> 1.0) @@ -87,175 +104,197 @@ GEM couchrest (~> 1.1.3) mime-types (>= 1.15) tzinfo (>= 0.3.22) - couchrest_session_store (0.3.1) - actionpack (~> 3.0) + couchrest_session_store (0.4.1) + actionpack (~> 4.0) couchrest couchrest_model - cucumber (1.3.17) + cucumber (2.3.3) builder (>= 2.1.2) + cucumber-core (~> 1.4.0) + cucumber-wire (~> 0.0.1) diff-lcs (>= 1.1.3) - gherkin (~> 2.12) + gherkin (~> 3.2.0) multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.1) - cucumber-rails (1.4.2) + multi_test (>= 0.1.2) + cucumber-core (1.4.0) + gherkin (~> 3.2.0) + cucumber-rails (1.4.3) capybara (>= 1.1.2, < 3) - cucumber (>= 1.3.8, < 2) - mime-types (>= 1.16, < 3) + cucumber (>= 1.3.8, < 3) + mime-types (>= 1.16, < 4) nokogiri (~> 1.5) - rails (>= 3, < 5) - daemons (1.1.9) + railties (>= 3, < 5) + cucumber-wire (0.0.1) + daemons (1.2.3) debug_inspector (0.0.2) diff-lcs (1.2.5) erubis (2.7.0) - eventmachine (1.0.3) - execjs (2.2.2) - factory_girl (4.5.0) + eventmachine (1.2.0.1) + execjs (2.6.0) + factory_girl (4.7.0) activesupport (>= 3.0.0) - factory_girl_rails (4.5.0) - factory_girl (~> 4.5.0) + factory_girl_rails (4.7.0) + factory_girl (~> 4.7.0) railties (>= 3.0.0) - fake_braintree (0.7.0) + fake_braintree (0.8.0) activesupport braintree (~> 2.32) - capybara (>= 2.0.3) + capybara (>= 2.2.0) sinatra - faker (1.4.3) + faker (1.6.3) i18n (~> 0.5) - ffi (1.9.6) - gherkin (2.12.2) - multi_json (~> 1.3) - haml (4.0.6) + ffi (1.9.10) + gherkin (3.2.0) + globalid (0.3.6) + activesupport (>= 4.1.0) + haml (4.0.7) tilt - haml-rails (0.4) - actionpack (>= 3.1, < 4.1) - activesupport (>= 3.1, < 4.1) - haml (>= 3.1, < 4.1) - railties (>= 3.1, < 4.1) - hike (1.2.3) - http_accept_language (2.0.2) + haml-rails (0.9.0) + actionpack (>= 4.0.1) + activesupport (>= 4.0.1) + haml (>= 4.0.6, < 5.0) + html2haml (>= 1.0.1) + railties (>= 4.0.1) + html2haml (2.0.0) + erubis (~> 2.7.0) + haml (~> 4.0.0) + nokogiri (~> 1.6.0) + ruby_parser (~> 3.5) + http_accept_language (2.0.5) i18n (0.7.0) i18n-missing_translations (0.0.1) - journey (1.0.4) - jquery-rails (3.1.2) - railties (>= 3.0, < 5.0) + jquery-rails (4.1.1) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) thor (>= 0.14, < 2.0) + js_regex (1.0.14) + regexp_parser (= 0.3.3) json (1.8.3) - kaminari (0.13.0) + kaminari (0.16.3) actionpack (>= 3.0.0) activesupport (>= 3.0.0) - railties (>= 3.0.0) launchy (2.4.3) addressable (~> 2.3) - libv8 (3.16.14.11) - mail (2.5.4) - mime-types (~> 1.16) - treetop (~> 1.4.8) + libv8 (3.16.14.15) + loofah (2.0.3) + nokogiri (>= 1.5.9) + mail (2.6.4) + mime-types (>= 1.16, < 4) metaclass (0.0.4) method_source (0.8.2) mime-types (1.25.1) - mini_portile (0.6.1) - minitest-stub-const (0.2) - mocha (0.13.3) + mini_portile2 (2.0.0) + minitest (5.8.4) + minitest-stub-const (0.5) + mocha (1.1.0) metaclass (~> 0.0.1) - multi_json (1.11.2) - multi_test (0.1.1) - nokogiri (1.6.5) - mini_portile (~> 0.6.0) - phantomjs-binaries (1.9.2.4) + multi_json (1.11.3) + multi_test (0.1.2) + nokogiri (1.6.7.2) + mini_portile2 (~> 2.0.0.rc2) + phantomjs-binaries (2.1.1.0) sys-uname (= 0.9.0) - poltergeist (1.5.1) + poltergeist (1.9.0) capybara (~> 2.1) cliver (~> 0.3.1) multi_json (~> 1.0) websocket-driver (>= 0.2.0) - polyglot (0.3.5) - pry (0.10.1) + pry (0.10.3) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - quiet_assets (1.0.3) + quiet_assets (1.1.0) railties (>= 3.1, < 5.0) - rack (1.4.7) - rack-cache (1.6.1) - rack (>= 0.4) + rack (1.6.4) rack-protection (1.5.3) rack - rack-ssl (1.3.4) - rack rack-test (0.6.3) rack (>= 1.0) - rails (3.2.22.2) - actionmailer (= 3.2.22.2) - actionpack (= 3.2.22.2) - activerecord (= 3.2.22.2) - activeresource (= 3.2.22.2) - activesupport (= 3.2.22.2) - bundler (~> 1.0) - railties (= 3.2.22.2) - rails-i18n (3.0.1) - i18n (~> 0.5) - rails (>= 3.0.0, < 4.0.0) + rails (4.2.6) + actionmailer (= 4.2.6) + actionpack (= 4.2.6) + actionview (= 4.2.6) + activejob (= 4.2.6) + activemodel (= 4.2.6) + activerecord (= 4.2.6) + activesupport (= 4.2.6) + bundler (>= 1.3.0, < 2.0) + railties (= 4.2.6) + sprockets-rails + rails-deprecated_sanitizer (1.0.3) + activesupport (>= 4.2.0.alpha) + rails-dom-testing (1.0.7) + activesupport (>= 4.2.0.beta, < 5.0) + nokogiri (~> 1.6.0) + rails-deprecated_sanitizer (>= 1.0.1) + rails-html-sanitizer (1.0.3) + loofah (~> 2.0) + rails-i18n (4.0.8) + i18n (~> 0.7) + railties (~> 4.0) rails_warden (0.5.8) warden (>= 1.0.0) - railties (3.2.22.2) - actionpack (= 3.2.22.2) - activesupport (= 3.2.22.2) - rack-ssl (~> 1.3.2) + railties (4.2.6) + actionpack (= 4.2.6) + activesupport (= 4.2.6) rake (>= 0.8.7) - rdoc (~> 3.4) - thor (>= 0.14.6, < 2.0) - rake (10.5.0) - rdiscount (2.1.7.1) - rdoc (3.12.2) - json (~> 1.4) + thor (>= 0.18.1, < 2.0) + rake (11.1.2) + rdiscount (2.1.8) ref (2.0.0) + regexp_parser (0.3.3) rest-client (1.6.9) mime-types (~> 1.16) ruby-srp (0.2.1) - sass (3.4.9) - sass-rails (3.2.6) - railties (~> 3.2.0) - sass (>= 3.1.10) - tilt (~> 1.3) - simple_form (2.1.2) - actionpack (~> 3.0) - activemodel (~> 3.0) - sinatra (1.4.5) - rack (~> 1.4) + ruby_parser (3.8.1) + sexp_processor (~> 4.1) + sass (3.4.22) + sass-rails (5.0.4) + railties (>= 4.0.0, < 5.0) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) + sexp_processor (4.7.0) + simple_form (3.2.1) + actionpack (> 4, < 5.1) + activemodel (> 4, < 5.1) + sinatra (1.4.7) + rack (~> 1.5) rack-protection (~> 1.4) - tilt (~> 1.3, >= 1.3.4) + tilt (>= 1.3, < 3) slop (3.6.0) - sprockets (2.2.3) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) + sprockets (3.6.0) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.0.4) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) sys-uname (0.9.0) ffi (>= 1.0.0) therubyracer (0.12.2) libv8 (~> 3.16.14.0) ref - thin (1.6.3) + thin (1.6.4) daemons (~> 1.0, >= 1.0.9) - eventmachine (~> 1.0) + eventmachine (~> 1.0, >= 1.0.4) rack (~> 1.0) thor (0.19.1) - tilt (1.4.1) - treetop (1.4.15) - polyglot - polyglot (>= 0.3.1) - tzinfo (0.3.47) - uglifier (1.2.7) - execjs (>= 0.3.0) - multi_json (~> 1.3) - valid_email (0.0.7) + thread_safe (0.3.5) + tilt (2.0.2) + tzinfo (1.2.2) + thread_safe (~> 0.1) + uglifier (3.0.0) + execjs (>= 0.3.0, < 3) + valid_email (0.0.13) activemodel - mail - warden (1.2.3) + mail (~> 2.6.1) + warden (1.2.6) rack (>= 1.0) - websocket-driver (0.5.1) + websocket-driver (0.6.3) websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.1) + websocket-extensions (0.1.2) xpath (2.0.0) nokogiri (~> 1.3) @@ -264,9 +303,9 @@ PLATFORMS DEPENDENCIES SyslogLogger (~> 2.0) - better_errors (= 1.1.0) + better_errors binding_of_caller - bootstrap-sass (= 2.3.2.2) + bootstrap-sass byebug capybara certificate_authority! @@ -275,36 +314,36 @@ DEPENDENCIES common_languages! couchrest (~> 1.1.3) couchrest_model (~> 2.0.0) - couchrest_session_store (= 0.3.1) + couchrest_session_store (~> 0.4.1) cucumber-rails factory_girl_rails fake_braintree faker - haml-rails (= 0.4.0) + haml-rails http_accept_language i18n-missing_translations jquery-rails - kaminari (= 0.13.0) + kaminari launchy leap_web_billing! leap_web_help! minitest-stub-const - mocha (~> 0.13.0) + mocha phantomjs-binaries poltergeist pry quiet_assets - rails (~> 3.2.21) + rails (~> 4.2.6) rails-i18n rails_warden - rake (~> 10.4) + rake rdiscount ruby-srp (~> 0.2.1) - sass-rails (~> 3.2.5) + sass-rails simple_form - therubyracer (~> 0.12.2) + therubyracer thin - uglifier (~> 1.2.7) + uglifier valid_email BUNDLED WITH diff --git a/Gemfile.orig b/Gemfile.orig new file mode 100644 index 0000000..b7e83aa --- /dev/null +++ b/Gemfile.orig @@ -0,0 +1,119 @@ +source 'https://rubygems.org' + +require File.expand_path('../lib/gemfile_tools.rb', __FILE__) + +## CORE +# rake 11.x throws lots of warnings about rails 3.2 code +gem "rake" +gem "rails", "~> 4.2.6" +gem "couchrest", "~> 1.1.3" +gem "couchrest_model", "~> 2.0.0" +if ARGV.grep(/assets:precompile/).empty? +<<<<<<< HEAD + gem "couchrest_session_store", "= 0.3.1" +======= + gem "couchrest_session_store", "= 0.4.0", + path: '../couchrest_session_store' +>>>>>>> upgrade: use recent gems - broken +end + +## AUTHENTICATION +gem "ruby-srp", "~> 0.2.1" +gem "rails_warden" + +## CRYPTO +# we need certificate_authority v2.0, but was never released to rubygems, +# and travis does not work well with github sources, so vendored here: +gem 'certificate_authority', :path => 'vendor/gems/certificate_authority' + +## LOCALIZATION +gem 'http_accept_language' +gem 'rails-i18n' # locale files for built-in validation messages and times + # https://github.com/svenfuchs/rails-i18n + # for a list of keys: + # https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/en.yml +gem 'common_languages', :path => 'vendor/gems/common_languages' + +## VIEWS +gem 'kaminari' +gem 'rdiscount' # for rendering .md templates + +## ASSETS +gem "jquery-rails" +gem "simple_form" +gem 'client_side_validations' +gem 'client_side_validations-simple_form' +gem "haml-rails" +gem "bootstrap-sass" +gem "sass-rails" +gem 'quiet_assets' # stops logging all the asset requests +group :production do + gem "uglifier" + gem 'therubyracer', :platforms => :ruby + # ^^ See https://github.com/sstephenson/execjs#readme + # for list of supported runtimes. +end + +## +## ENVIRONMENT SPECIFIC GEMS +## + +group :test do + # integration testing + gem 'capybara', require: false + gem 'poltergeist' # headless js + gem 'launchy' # save_and_open_page + gem 'phantomjs-binaries' # binaries specific to the os + + # moching and stubbing + gem 'mocha', :require => false + gem 'minitest-stub-const' # why? + + # generating test data + gem 'factory_girl_rails' # test data factories + gem 'faker' # names and numbers for test data + + # billing tests + gem 'fake_braintree', require: false + + # we use cucumber to document and test the api + gem 'cucumber-rails', require: false +end + +group :test, :development do + gem 'thin' + gem 'i18n-missing_translations' + gem 'pry' +end + +group :production do + gem 'SyslogLogger', '~> 2.0' +end + +group :development do + gem "better_errors" + gem "binding_of_caller" +end + +group :test, :debug do + # bundler on jessie doesn't support `:platforms => :ruby_21` + gem 'byebug' +end + +## +## OPTIONAL GEMS AND ENGINES +## + +enabled_engines.each do |name, gem_info| + gem gem_info[:name], :path => gem_info[:path], :groups => gem_info[:env] +end + +custom_gems.each do |name, gem_info| + gem gem_info[:name], :path => gem_info[:path] +end + +## +## DEPENDENCIES FOR OPTIONAL ENGINES +## + +gem 'valid_email' # used by leap_web_help -- cgit v1.2.3 From 5407ef5b377a205f6012b2d6725b810eff93d9e6 Mon Sep 17 00:00:00 2001 From: Azul Date: Wed, 23 Mar 2016 21:31:33 +0100 Subject: upgrade: drop active_resource in config/application --- config/application.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/config/application.rb b/config/application.rb index b13c7d9..4771f89 100644 --- a/config/application.rb +++ b/config/application.rb @@ -4,7 +4,6 @@ require File.expand_path('../boot', __FILE__) # require "active_record/railtie" require "action_controller/railtie" require "action_mailer/railtie" -require "active_resource/railtie" require "sprockets/railtie" require "rails/test_unit/railtie" -- cgit v1.2.3 From abf600089a4bc4b5c7271e17b1fd95a95deb293f Mon Sep 17 00:00:00 2001 From: Azul Date: Wed, 23 Mar 2016 21:35:08 +0100 Subject: upgrade: couchrest 2.0.0.rc3 couchrest model 2.1.0.beta2 The latter supports Active Model >= 4.1 --- Gemfile | 4 ++-- Gemfile.lock | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Gemfile b/Gemfile index 5b5a33b..071dd3c 100644 --- a/Gemfile +++ b/Gemfile @@ -6,8 +6,8 @@ require File.expand_path('../lib/gemfile_tools.rb', __FILE__) # rake 11.x throws lots of warnings about rails 3.2 code gem "rake" gem "rails", "~> 4.2.6" -gem "couchrest", "~> 1.1.3" -gem "couchrest_model", "~> 2.0.0" +gem "couchrest", "~> 2.0.0.rc3" +gem "couchrest_model", "~> 2.1.0.beta2" if ARGV.grep(/assets:precompile/).empty? gem "couchrest_session_store", "~> 0.4.1" end diff --git a/Gemfile.lock b/Gemfile.lock index 3344b5c..0d18875 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -95,14 +95,13 @@ GEM cliver (0.3.2) coderay (1.1.1) concurrent-ruby (1.0.1) - couchrest (1.1.3) - mime-types (~> 1.15) - multi_json (~> 1.0) - rest-client (~> 1.6.1) - couchrest_model (2.0.1) - activemodel (>= 3.0) - couchrest (~> 1.1.3) + couchrest (2.0.0.rc3) + httpclient (~> 2.7) mime-types (>= 1.15) + multi_json (~> 1.7) + couchrest_model (2.1.0.beta2) + activemodel (~> 4.0) + couchrest (= 2.0.0.rc3) tzinfo (>= 0.3.22) couchrest_session_store (0.4.1) actionpack (~> 4.0) @@ -161,6 +160,7 @@ GEM nokogiri (~> 1.6.0) ruby_parser (~> 3.5) http_accept_language (2.0.5) + httpclient (2.8.0) i18n (0.7.0) i18n-missing_translations (0.0.1) jquery-rails (4.1.1) @@ -182,7 +182,9 @@ GEM mime-types (>= 1.16, < 4) metaclass (0.0.4) method_source (0.8.2) - mime-types (1.25.1) + mime-types (3.0) + mime-types-data (~> 3.2015) + mime-types-data (3.2016.0221) mini_portile2 (2.0.0) minitest (5.8.4) minitest-stub-const (0.5) @@ -243,8 +245,6 @@ GEM rdiscount (2.1.8) ref (2.0.0) regexp_parser (0.3.3) - rest-client (1.6.9) - mime-types (~> 1.16) ruby-srp (0.2.1) ruby_parser (3.8.1) sexp_processor (~> 4.1) @@ -312,8 +312,8 @@ DEPENDENCIES client_side_validations client_side_validations-simple_form common_languages! - couchrest (~> 1.1.3) - couchrest_model (~> 2.0.0) + couchrest (~> 2.0.0.rc3) + couchrest_model (~> 2.1.0.beta2) couchrest_session_store (~> 0.4.1) cucumber-rails factory_girl_rails -- cgit v1.2.3 From 065859b90cc5ef403b8f47bd5394b343e556cc4d Mon Sep 17 00:00:00 2001 From: Azul Date: Wed, 23 Mar 2016 21:48:52 +0100 Subject: upgrade: remove references to RestClient CouchRest > 1.2 does not use RestClient anymore. So we should not try to catch its errors. --- app/controllers/application_controller.rb | 2 +- app/models/token.rb | 4 +- config/initializers/error_constants.rb | 5 + config/initializers/validations.rb | 4 - engines/support/app/models/ticket.rb | 2 +- engines/support/test/unit/ticket_test.rb | 2 +- lib/extensions/couchrest.rb | 2 +- .../lib/couchrest/model/database_method.rb | 131 ++++++++++ .../lib/couchrest/model/rotation.rb | 263 +++++++++++++++++++++ .../lib/couchrest/session/document.rb | 119 ++++++++++ .../lib/couchrest/session/store.rb | 94 ++++++++ .../test/database_method_test.rb | 116 +++++++++ .../test/session_store_test.rb | 168 +++++++++++++ 13 files changed, 902 insertions(+), 10 deletions(-) delete mode 100644 config/initializers/validations.rb create mode 100644 vendor/gems/couchrest_session_store/lib/couchrest/model/database_method.rb create mode 100644 vendor/gems/couchrest_session_store/lib/couchrest/model/rotation.rb create mode 100644 vendor/gems/couchrest_session_store/lib/couchrest/session/document.rb create mode 100644 vendor/gems/couchrest_session_store/lib/couchrest/session/store.rb create mode 100644 vendor/gems/couchrest_session_store/test/database_method_test.rb create mode 100644 vendor/gems/couchrest_session_store/test/session_store_test.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 079dc18..2af2f29 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base before_filter :no_frame_header before_filter :language_header rescue_from StandardError, :with => :default_error_handler - rescue_from RestClient::Exception, :with => :default_error_handler + rescue_from CouchRest::Exception, :with => :default_error_handler ActiveSupport.run_load_hooks(:application_controller, self) diff --git a/app/models/token.rb b/app/models/token.rb index b398fcb..8ac32b8 100644 --- a/app/models/token.rb +++ b/app/models/token.rb @@ -59,8 +59,8 @@ class Token < CouchRest::Model::Base # So let's make sure we don't crash if they disappeared def destroy_with_rescue destroy_without_rescue - rescue RestClient::ResourceNotFound # do nothing it's gone already - rescue RestClient::Conflict # do nothing - it's been updated - #7670 + rescue CouchRest::NotFound + rescue CouchRest::Conflict # do nothing - it's been updated - #7670 end alias_method_chain :destroy, :rescue diff --git a/config/initializers/error_constants.rb b/config/initializers/error_constants.rb index fdd3624..bf2dad4 100644 --- a/config/initializers/error_constants.rb +++ b/config/initializers/error_constants.rb @@ -1,3 +1,8 @@ require 'ruby-srp' WRONG_PASSWORD = SRP::WrongPassword + +# In case we use a different ORM at some point +VALIDATION_FAILED = CouchRest::Model::Errors::Validations +RECORD_NOT_FOUND = CouchRest::Model::DocumentNotFound +RESOURCE_NOT_FOUDN = CouchRest::NotFound diff --git a/config/initializers/validations.rb b/config/initializers/validations.rb deleted file mode 100644 index e8acfbe..0000000 --- a/config/initializers/validations.rb +++ /dev/null @@ -1,4 +0,0 @@ -# In case we use a different ORM at some point -VALIDATION_FAILED = CouchRest::Model::Errors::Validations -RECORD_NOT_FOUND = CouchRest::Model::DocumentNotFound -RESOURCE_NOT_FOUND = RestClient::ResourceNotFound diff --git a/engines/support/app/models/ticket.rb b/engines/support/app/models/ticket.rb index b1bdf8d..4615a10 100644 --- a/engines/support/app/models/ticket.rb +++ b/engines/support/app/models/ticket.rb @@ -50,7 +50,7 @@ class Ticket < CouchRest::Model::Base self.by_created_by.key(user.id).each do |ticket| ticket.destroy end - rescue RestClient::ResourceNotFound + rescue RESOURCE_NOT_FOUND # silently ignore if design docs are not yet created end diff --git a/engines/support/test/unit/ticket_test.rb b/engines/support/test/unit/ticket_test.rb index 7b5281f..c2c5e11 100644 --- a/engines/support/test/unit/ticket_test.rb +++ b/engines/support/test/unit/ticket_test.rb @@ -63,7 +63,7 @@ class TicketTest < ActiveSupport::TestCase test "find tickets user commented on" do # clear old tickets just in case - # this will cause RestClient::ResourceNotFound errors if there are multiple copies of the same ticket returned + # this will cause RESOURCE_NOT_FOUND errors if there are multiple copies of the same ticket returned Ticket.by_includes_post_by.key('123').each {|t| t.destroy} # TODO: the by_includes_post_by view is only used for tests. Maybe we should get rid of it and change the test to including ordering? diff --git a/lib/extensions/couchrest.rb b/lib/extensions/couchrest.rb index cc041e0..6967980 100644 --- a/lib/extensions/couchrest.rb +++ b/lib/extensions/couchrest.rb @@ -81,7 +81,7 @@ module CouchRest class ModelRailtie config.action_dispatch.rescue_responses.merge!( 'CouchRest::Model::DocumentNotFound' => :not_found, - 'RestClient::ResourceNotFound' => :not_found + 'CouchRest::NotFound' => :not_found ) end end diff --git a/vendor/gems/couchrest_session_store/lib/couchrest/model/database_method.rb b/vendor/gems/couchrest_session_store/lib/couchrest/model/database_method.rb new file mode 100644 index 0000000..6ecc8f3 --- /dev/null +++ b/vendor/gems/couchrest_session_store/lib/couchrest/model/database_method.rb @@ -0,0 +1,131 @@ +# +# Allow setting the database to happen dynamically. +# +# Unlike normal CouchRest::Model, the database is not automatically created +# unless you call database!() +# +# The method specified by `database_method` must exist as a class method but +# may optionally also exist as an instance method. +# + +module CouchRest + module Model + module DatabaseMethod + extend ActiveSupport::Concern + + def database + if self.class.database_method + self.class.server.database(call_database_method) + else + self.class.database + end + end + + def database! + if self.class.database_method + self.class.server.database!(call_database_method) + else + self.class.database! + end + end + + def database_exists?(db_name) + self.class.database_exists?(db_name) + end + + # + # The normal CouchRest::Model::Base comparison checks if the model's + # database objects are the same. That is not good for use here, since + # the objects will always be different. Instead, we compare the string + # that each database evaluates to. + # + def ==(other) + return false unless other.is_a?(Base) + if id.nil? && other.id.nil? + to_hash == other.to_hash + else + id == other.id && database.to_s == other.database.to_s + end + end + alias :eql? :== + + protected + + def call_database_method + if self.respond_to?(self.class.database_method) + name = self.send(self.class.database_method) + self.class.db_name_with_prefix(name) + else + self.class.send(:call_database_method) + end + end + + module ClassMethods + + def database_method(method = nil) + if method + @database_method = method + end + @database_method + end + alias :use_database_method :database_method + + def database + if database_method + if !self.respond_to?(database_method) + raise ArgumentError.new("Incorrect argument to database_method(): no such method '#{method}' found in class #{self}.") + end + self.server.database(call_database_method) + else + @database ||= prepare_database(super) + end + end + + def database! + if database_method + self.server.database!(call_database_method) + else + @database ||= prepare_database(super) + end + end + + # + # same as database(), but allows for an argument that gets passed through to + # database method. + # + def choose_database(*args) + self.server.database(call_database_method(*args)) + end + + def db_name_with_prefix(name) + conf = self.send(:connection_configuration) + [conf[:prefix], name, conf[:suffix]].reject{|i|i.to_s.empty?}.join(conf[:join]) + end + + def database_exists?(name) + name = db_name_with_prefix(name) + begin + CouchRest.head "#{self.server.uri}/#{name}" + return true + rescue CouchRest::NotFound + return false + end + end + + protected + + def call_database_method(*args) + name = nil + method = self.method(database_method) + if method.arity == 0 + name = method.call + else + name = method.call(*args) + end + db_name_with_prefix(name) + end + + end + end + end +end diff --git a/vendor/gems/couchrest_session_store/lib/couchrest/model/rotation.rb b/vendor/gems/couchrest_session_store/lib/couchrest/model/rotation.rb new file mode 100644 index 0000000..9e1a5c3 --- /dev/null +++ b/vendor/gems/couchrest_session_store/lib/couchrest/model/rotation.rb @@ -0,0 +1,263 @@ +module CouchRest + module Model + module Rotation + extend ActiveSupport::Concern + include CouchRest::Model::DatabaseMethod + + included do + use_database_method :rotated_database_name + end + + def create(*args) + super(*args) + rescue CouchRest::NotFound => exc + raise storage_missing(exc) + end + + def update(*args) + super(*args) + rescue CouchRest::NotFound => exc + raise storage_missing(exc) + end + + def destroy(*args) + super(*args) + rescue CouchRest::NotFound => exc + raise storage_missing(exc) + end + + private + + # returns a special 'storage missing' exception when the db has + # not been created. very useful, since this happens a lot and a + # generic 404 is not that helpful. + def storage_missing(exc) + if exc.http_body =~ /no_db_file/ + CouchRest::StorageMissing.new(exc.response, database) + else + exc + end + end + + public + + module ClassMethods + # + # Set up database rotation. + # + # base_name -- the name of the db before the rotation number is + # appended. + # + # options -- one of: + # + # * :every -- frequency of rotation + # * :expiration_field - what field to use to determine if a + # document is expired. + # * :timestamp_field - alternately, what field to use for the + # document timestamp. + # * :timeout -- used to expire documents with only a timestamp + # field (in minutes) + # + def rotate_database(base_name, options={}) + @rotation_base_name = base_name + @rotation_every = (options.delete(:every) || 30.days).to_i + @expiration_field = options.delete(:expiration_field) + @timestamp_field = options.delete(:timestamp_field) + @timeout = options.delete(:timeout) + if options.any? + raise ArgumentError.new('Could not understand options %s' % options.keys) + end + end + + # + # Check to see if dbs should be rotated. The :window + # argument specifies how far in advance we should + # create the new database (default 1.day). + # + # This method relies on the assumption that it is called + # at least once within each @rotation_every period. + # + def rotate_database_now(options={}) + window = options[:window] || 1.day + + now = Time.now.utc + current_name = rotated_database_name(now) + current_count = now.to_i/@rotation_every + + next_time = window.from_now.utc + next_name = rotated_database_name(next_time) + next_count = current_count+1 + + prev_name = current_name.sub(/(\d+)$/) {|i| i.to_i-1} + replication_started = false + old_name = prev_name.sub(/(\d+)$/) {|i| i.to_i-1} # even older than prev_name + trailing_edge_time = window.ago.utc + + if !database_exists?(current_name) + # we should have created the current db earlier, but if somehow + # it is missing we must make sure it exists. + create_new_rotated_database(:from => prev_name, :to => current_name) + replication_started = true + end + + if next_time.to_i/@rotation_every >= next_count && !database_exists?(next_name) + # time to create the next db in advance of actually needing it. + create_new_rotated_database(:from => current_name, :to => next_name) + end + + if trailing_edge_time.to_i/@rotation_every == current_count + # delete old dbs, but only after window time has past since the last rotation + if !replication_started && database_exists?(prev_name) + # delete previous, but only if we didn't just start replicating from it + self.server.database(db_name_with_prefix(prev_name)).delete! + end + if database_exists?(old_name) + # there are some edge cases, when rotate_database_now is run + # infrequently, that an older db might be left around. + self.server.database(db_name_with_prefix(old_name)).delete! + end + end + end + + def rotated_database_name(time=nil) + unless @rotation_base_name && @rotation_every + raise ArgumentError.new('missing @rotation_base_name or @rotation_every') + end + time ||= Time.now.utc + units = time.to_i / @rotation_every.to_i + "#{@rotation_base_name}_#{units}" + end + + # + # create a new empty database. + # + def create_database!(name=nil) + db = if name + self.server.database!(db_name_with_prefix(name)) + else + self.database! + end + create_rotation_filter(db) + if self.respond_to?(:design_doc) + design_doc.sync!(db) + # or maybe this?: + #self.design_docs.each do |design| + # design.migrate(to_db) + #end + end + return db + end + + protected + + # + # Creates database named by options[:to]. Optionally, set up + # continuous replication from the options[:from] db, if it exists. The + # assumption is that the from db will be destroyed later, cleaning up + # the replication once it is no longer needed. + # + # This method will also copy design documents if present in the from + # db, in the CouchRest::Model, or in a database named after + # @rotation_base_name. + # + def create_new_rotated_database(options={}) + from = options[:from] + to = options[:to] + to_db = self.create_database!(to) + if database_exists?(@rotation_base_name) + base_db = self.server.database(db_name_with_prefix(@rotation_base_name)) + copy_design_docs(base_db, to_db) + end + if from && from != to && database_exists?(from) + from_db = self.server.database(db_name_with_prefix(from)) + replicate_old_to_new(from_db, to_db) + end + end + + def copy_design_docs(from, to) + params = {:startkey => '_design/', :endkey => '_design0', :include_docs => true} + from.documents(params) do |doc_hash| + design = doc_hash['doc'] + begin + to.get(design['_id']) + rescue CouchRest::NotFound + design.delete('_rev') + to.save_doc(design) + end + end + end + + def create_rotation_filter(db) + name = 'rotation_filter' + filter_string = if @expiration_field + NOT_EXPIRED_FILTER % {:expires => @expiration_field} + elsif @timestamp_field && @timeout + NOT_TIMED_OUT_FILTER % {:timestamp => @timestamp_field, :timeout => (60 * @timeout)} + else + NOT_DELETED_FILTER + end + filters = {"not_expired" => filter_string} + db.save_doc("_id" => "_design/#{name}", "filters" => filters) + rescue CouchRest::Conflict + end + + # + # Replicates documents from_db to to_db, skipping documents that have + # expired or been deleted. + # + # NOTE: It would be better if we could do this: + # + # from_db.replicate_to(to_db, true, false, + # :filter => 'rotation_filter/not_expired') + # + # But replicate_to() does not support a filter argument, so we call + # the private method replication() directly. + # + def replicate_old_to_new(from_db, to_db) + create_rotation_filter(from_db) + from_db.send(:replicate, to_db, true, :source => from_db.name, :filter => 'rotation_filter/not_expired') + end + + # + # Three different filters, depending on how the model is set up. + # + # NOT_EXPIRED_FILTER is used when there is a single field that + # contains an absolute time for when the document has expired. The + # + # NOT_TIMED_OUT_FILTER is used when there is a field that records the + # timestamp of the last time the document was used. The expiration in + # this case is calculated from the timestamp plus @timeout. + # + # NOT_DELETED_FILTER is used when the other two cannot be. + # + NOT_EXPIRED_FILTER = "" + +%[function(doc, req) { + if (doc._deleted) { + return false; + } else if (typeof(doc.%{expires}) != "undefined") { + return Date.now() < (new Date(doc.%{expires})).getTime(); + } else { + return true; + } +}] + + NOT_TIMED_OUT_FILTER = "" + +%[function(doc, req) { + if (doc._deleted) { + return false; + } else if (typeof(doc.%{timestamp}) != "undefined") { + return Date.now() < (new Date(doc.%{timestamp})).getTime() + %{timeout}; + } else { + return true; + } +}] + + NOT_DELETED_FILTER = "" + +%[function(doc, req) { + return !doc._deleted; +}] + + end + end + end +end diff --git a/vendor/gems/couchrest_session_store/lib/couchrest/session/document.rb b/vendor/gems/couchrest_session_store/lib/couchrest/session/document.rb new file mode 100644 index 0000000..b1e73cc --- /dev/null +++ b/vendor/gems/couchrest_session_store/lib/couchrest/session/document.rb @@ -0,0 +1,119 @@ +require 'couchrest/session/utility' +require 'time' + +class CouchRest::Session::Document < CouchRest::Document + include CouchRest::Model::Configuration + include CouchRest::Model::Connection + include CouchRest::Session::Utility + include CouchRest::Model::Rotation + + rotate_database 'sessions', + :every => 1.month, :expiration_field => :expires + + def self.fetch(sid) + self.allocate.tap do |session_doc| + session_doc.fetch(sid) + end + end + + def self.build(sid, session, options = {}) + self.new(CouchRest::Document.new({"_id" => sid})).tap do |session_doc| + session_doc.update session, options + end + end + + def self.build_or_update(sid, session, options = {}) + options[:marshal_data] = true if options[:marshal_data].nil? + doc = self.fetch(sid) + doc.update(session, options) + return doc + rescue CouchRest::NotFound + self.build(sid, session, options) + end + + def self.find_by_expires(options = {}) + options[:reduce] ||= false + design = database.get '_design/Session' + response = design.view :by_expires, options + response['rows'] + end + + def self.create_database!(name=nil) + db = super(name) + begin + db.get('_design/Session') + rescue CouchRest::NotFound + design = File.read(File.expand_path('../../../../design/Session.json', __FILE__)) + design = JSON.parse(design) + db.save_doc(design.merge({"_id" => "_design/Session"})) + end + db + end + + def initialize(doc) + @doc = doc + end + + def fetch(sid = nil) + @doc = database.get(sid || doc['_id']) + end + + def to_session + if doc["marshalled"] + session = unmarshal(doc["data"]) + else + session = doc["data"] + end + return session + end + + def delete + database.delete_doc(doc) + end + + def update(session, options) + # clean up old data but leave id and revision intact + doc.reject! do |k,v| + k[0] != '_' + end + doc.merge! data_for_doc(session, options) + end + + def save + database.save_doc(doc) + rescue CouchRest::Conflict + fetch + retry + rescue CouchRest::NotFound => exc + if exc.http_body =~ /no_db_file/ + exc = CouchRest::StorageMissing.new(exc.response, database) + end + raise exc + end + + def expired? + expires && expires < Time.now + end + + protected + + def data_for_doc(session, options) + { "data" => options[:marshal_data] ? marshal(session) : session, + "marshalled" => options[:marshal_data], + "expires" => expiry_from_options(options) } + end + + def expiry_from_options(options) + expire_after = options[:expire_after] + expire_after && (Time.now + expire_after).utc + end + + def expires + doc["expires"] && Time.iso8601(doc["expires"]) + end + + def doc + @doc + end + +end diff --git a/vendor/gems/couchrest_session_store/lib/couchrest/session/store.rb b/vendor/gems/couchrest_session_store/lib/couchrest/session/store.rb new file mode 100644 index 0000000..f209f54 --- /dev/null +++ b/vendor/gems/couchrest_session_store/lib/couchrest/session/store.rb @@ -0,0 +1,94 @@ +class CouchRest::Session::Store < ActionDispatch::Session::AbstractStore + + # delegate configure to document + def self.configure(*args, &block) + CouchRest::Session::Document.configure *args, &block + end + + def self.set_options(options) + @options = options + if @options[:database] + CouchRest::Session::Document.use_database @options[:database] + end + end + + def initialize(app, options = {}) + super + self.class.set_options(options) + end + + def cleanup(rows) + rows.each do |row| + doc = CouchRest::Session::Document.fetch(row['id']) + doc.delete + end + end + + def expired + CouchRest::Session::Document.find_by_expires startkey: 1, + endkey: Time.now.utc.iso8601 + end + + def never_expiring + CouchRest::Session::Document.find_by_expires endkey: 1 + end + + private + + def get_session(env, sid) + if session = fetch_session(sid) + [sid, session] + else + [generate_sid, {}] + end + rescue CouchRest::NotFound + # session data does not exist anymore + return [sid, {}] + rescue CouchRest::Unauthorized, + Errno::EHOSTUNREACH, + Errno::ECONNREFUSED => e + # can't connect to couch. We add some status to the session + # so the app can react. (Display error for example) + return [sid, {"_status" => {"couch" => "unreachable"}}] + end + + def set_session(env, sid, session, options) + raise CouchRest::NotFound if /^_design\/(.*)/ =~ sid + doc = build_or_update_doc(sid, session, options) + doc.save + return sid + # if we can't store the session we just return false. + rescue CouchRest::Unauthorized, + Errno::EHOSTUNREACH, + Errno::ECONNREFUSED => e + return false + end + + def destroy_session(env, sid, options) + doc = secure_get(sid) + doc.delete + generate_sid unless options[:drop] + rescue CouchRest::NotFound + # already destroyed - we're done. + generate_sid unless options[:drop] + end + + def fetch_session(sid) + return nil unless sid + doc = secure_get(sid) + doc.to_session unless doc.expired? + end + + def build_or_update_doc(sid, session, options) + CouchRest::Session::Document.build_or_update(sid, session, options) + end + + # prevent access to design docs + # this should be prevented on a couch permission level as well. + # but better be save than sorry. + def secure_get(sid) + raise CouchRest::NotFound if /^_design\/(.*)/ =~ sid + CouchRest::Session::Document.fetch(sid) + end + +end diff --git a/vendor/gems/couchrest_session_store/test/database_method_test.rb b/vendor/gems/couchrest_session_store/test/database_method_test.rb new file mode 100644 index 0000000..18985c3 --- /dev/null +++ b/vendor/gems/couchrest_session_store/test/database_method_test.rb @@ -0,0 +1,116 @@ +require_relative 'test_helper' + +class DatabaseMethodTest < MiniTest::Test + + class TestModel < CouchRest::Model::Base + include CouchRest::Model::DatabaseMethod + + use_database_method :db_name + property :dbname, String + property :confirm, String + + def db_name + "test_db_#{self[:dbname]}" + end + end + + def test_instance_method + doc1 = TestModel.new({:dbname => 'one'}) + doc1.database.create! + assert doc1.database.root.ends_with?('test_db_one') + assert doc1.save + doc1.update_attributes(:confirm => 'yep') + + doc2 = TestModel.new({:dbname => 'two'}) + doc2.database.create! + assert doc2.database.root.ends_with?('test_db_two') + assert doc2.save + doc2.confirm = 'sure' + doc2.save! + + doc1_copy = CouchRest.get([doc1.database.root, doc1.id].join('/')) + assert_equal "yep", doc1_copy["confirm"] + + doc2_copy = CouchRest.get([doc2.database.root, doc2.id].join('/')) + assert_equal "sure", doc2_copy["confirm"] + + doc1.database.delete! + doc2.database.delete! + end + + def test_switch_db + doc_red = TestModel.new({:dbname => 'red', :confirm => 'rose'}) + doc_red.database.create! + root = doc_red.database.root + + doc_blue = doc_red.clone + doc_blue.dbname = 'blue' + doc_blue.database! + doc_blue.save! + + doc_blue_copy = CouchRest.get([root.sub('red','blue'), doc_blue.id].join('/')) + assert_equal "rose", doc_blue_copy["confirm"] + + doc_red.database.delete! + doc_blue.database.delete! + end + + # + # A test scenario for database_method in which some user accounts + # are stored in a seperate temporary database (so that the test + # accounts don't bloat the normal database). + # + + class User < CouchRest::Model::Base + include CouchRest::Model::DatabaseMethod + + use_database_method :db_name + property :login, String + before_save :create_db + + class << self + def get(id, db = database) + result = super(id, db) + if result.nil? + return super(id, choose_database('test-user')) + else + return result + end + end + alias :find :get + end + + protected + + def self.db_name(login = nil) + if !login.nil? && login =~ /test-user/ + 'tmp_users' + else + 'users' + end + end + + def db_name + self.class.db_name(self.login) + end + + def create_db + unless database_exists?(db_name) + self.database! + end + end + + end + + def test_tmp_user_db + user1 = User.new({:login => 'test-user-1'}) + assert user1.save + assert User.find(user1.id), 'should find user in tmp_users' + assert_equal user1.login, User.find(user1.id).login + assert_equal 'test-user-1', User.server.database('couchrest_tmp_users').get(user1.id)['login'] + assert_raises CouchRest::NotFound do + User.server.database('couchrest_users').get(user1.id) + end + end + +end diff --git a/vendor/gems/couchrest_session_store/test/session_store_test.rb b/vendor/gems/couchrest_session_store/test/session_store_test.rb new file mode 100644 index 0000000..4fbf30b --- /dev/null +++ b/vendor/gems/couchrest_session_store/test/session_store_test.rb @@ -0,0 +1,168 @@ +require File.expand_path(File.dirname(__FILE__) + '/test_helper') + +class SessionStoreTest < MiniTest::Test + + def test_session_initialization + sid, session = store.send :get_session, env, nil + assert sid + assert_equal Hash.new, session + end + + def test_normal_session_flow + sid, session = never_expiring_session + assert_equal [sid, session], store.send(:get_session, env, sid) + store.send :destroy_session, env, sid, {} + end + + def test_updating_session + sid, session = never_expiring_session + session[:bla] = "blub" + store.send :set_session, env, sid, session, {} + assert_equal [sid, session], store.send(:get_session, env, sid) + store.send :destroy_session, env, sid, {} + end + + def test_prevent_access_to_design_docs + sid = '_design/bla' + session = {views: 'my hacked view'} + assert_raises CouchRest::NotFound do + store_session(sid, session) + end + end + + def test_unmarshalled_session_flow + sid, session = init_session + store_session sid, session, :marshal_data => false + new_sid, new_session = store.send(:get_session, env, sid) + assert_equal sid, new_sid + assert_equal session[:key], new_session["key"] + store.send :destroy_session, env, sid, {} + end + + def test_unmarshalled_data + sid, session = init_session + store_session sid, session, :marshal_data => false + couch = CouchTester.new + data = couch.get(sid)["data"] + assert_equal session[:key], data["key"] + end + + def test_logout_in_between + sid, session = never_expiring_session + store.send :destroy_session, env, sid, {} + other_sid, other_session = store.send(:get_session, env, sid) + assert_equal Hash.new, other_session + end + + def test_can_logout_twice + sid, session = never_expiring_session + store.send :destroy_session, env, sid, {} + store.send :destroy_session, env, sid, {} + other_sid, other_session = store.send(:get_session, env, sid) + assert_equal Hash.new, other_session + end + + def test_stored_and_not_expired_yet + sid, session = expiring_session + doc = CouchRest::Session::Document.fetch(sid) + expires = doc.send :expires + assert expires + assert !doc.expired? + assert (expires - Time.now) > 0, "Exiry should be in the future" + assert (expires - Time.now) <= 300, "Should expire after 300 seconds - not more" + assert_equal [sid, session], store.send(:get_session, env, sid) + end + + def test_stored_but_expired + sid, session = expired_session + other_sid, other_session = store.send(:get_session, env, sid) + assert_equal Hash.new, other_session, "session should have expired" + assert other_sid != sid + end + + def test_find_expired_sessions + expired, expiring, never_expiring = seed_sessions + expired_session_ids = store.expired.map {|row| row['id']} + assert expired_session_ids.include?(expired) + assert !expired_session_ids.include?(expiring) + assert !expired_session_ids.include?(never_expiring) + end + + def test_find_never_expiring_sessions + expired, expiring, never_expiring = seed_sessions + never_expiring_session_ids = store.never_expiring.map {|row| row['id']} + assert never_expiring_session_ids.include?(never_expiring) + assert !never_expiring_session_ids.include?(expiring) + assert !never_expiring_session_ids.include?(expired) + end + + def test_cleanup_expired_sessions + sid, session = expired_session + store.cleanup(store.expired) + assert_raises CouchRest::NotFound do + CouchTester.new.get(sid) + end + end + + def test_keep_fresh_during_cleanup + sid, session = expiring_session + store.cleanup(store.expired) + assert_equal [sid, session], store.send(:get_session, env, sid) + end + + def test_store_without_expiry + sid, session = never_expiring_session + couch = CouchTester.new + assert_nil couch.get(sid)["expires"] + assert_equal [sid, session], store.send(:get_session, env, sid) + end + + def app + nil + end + + def store(options = {}) + @store ||= CouchRest::Session::Store.new(app, options) + end + + def env(settings = {}) + env ||= settings + end + + # returns the session ids of an expired, and expiring and a never + # expiring session + def seed_sessions + [expired_session, expiring_session, never_expiring_session].map(&:first) + end + + def never_expiring_session + store_session *init_session + end + + def expiring_session + sid, session = init_session + store_session(sid, session, expire_after: 300) + end + + def expired_session + expire_session *expiring_session + end + + def init_session + sid, session = store.send :get_session, env, nil + session[:key] = "stub" + return sid, session + end + + def store_session(sid, session, options = {}) + store.send :set_session, env, sid, session, options + return sid, session + end + + def expire_session(sid, session) + CouchTester.new.update sid, + "expires" => (Time.now - 10.minutes).utc.iso8601 + return sid, session + end + +end -- cgit v1.2.3 From 16da29309cdb117e2ac40eb93286fc265c3135d5 Mon Sep 17 00:00:00 2001 From: Azul Date: Wed, 23 Mar 2016 21:53:29 +0100 Subject: vendoring couchrest session store for development 0.4.0 has not been released yet. But travis needs it to run. So i vendor it for now. Will remove it again when the build is getting stable. --- Gemfile.lock | 8 ++ Gemfile.orig | 119 ------------------ vendor/gems/couchrest_session_store/.ruby-version | 1 + vendor/gems/couchrest_session_store/.travis.yml | 6 + vendor/gems/couchrest_session_store/Gemfile | 7 ++ vendor/gems/couchrest_session_store/README.md | 133 +++++++++++++++++++++ vendor/gems/couchrest_session_store/Rakefile | 9 ++ .../couchrest_session_store.gemspec | 25 ++++ .../couchrest_session_store/design/Session.json | 8 ++ .../lib/couchrest/session.rb | 15 +++ .../lib/couchrest/session/utility.rb | 12 ++ .../lib/couchrest_session_store.rb | 11 ++ .../couchrest_session_store/test/couch_tester.rb | 27 +++++ .../test/database_rotation_test.rb | 88 ++++++++++++++ .../test/session_document_test.rb | 27 +++++ .../couchrest_session_store/test/setup_couch.sh | 7 ++ .../couchrest_session_store/test/stress_test.rb | 51 ++++++++ .../couchrest_session_store/test/test_clock.rb | 12 ++ .../couchrest_session_store/test/test_helper.rb | 9 ++ 19 files changed, 456 insertions(+), 119 deletions(-) delete mode 100644 Gemfile.orig create mode 100644 vendor/gems/couchrest_session_store/.ruby-version create mode 100644 vendor/gems/couchrest_session_store/.travis.yml create mode 100644 vendor/gems/couchrest_session_store/Gemfile create mode 100644 vendor/gems/couchrest_session_store/README.md create mode 100644 vendor/gems/couchrest_session_store/Rakefile create mode 100644 vendor/gems/couchrest_session_store/couchrest_session_store.gemspec create mode 100644 vendor/gems/couchrest_session_store/design/Session.json create mode 100644 vendor/gems/couchrest_session_store/lib/couchrest/session.rb create mode 100644 vendor/gems/couchrest_session_store/lib/couchrest/session/utility.rb create mode 100644 vendor/gems/couchrest_session_store/lib/couchrest_session_store.rb create mode 100644 vendor/gems/couchrest_session_store/test/couch_tester.rb create mode 100644 vendor/gems/couchrest_session_store/test/database_rotation_test.rb create mode 100644 vendor/gems/couchrest_session_store/test/session_document_test.rb create mode 100755 vendor/gems/couchrest_session_store/test/setup_couch.sh create mode 100644 vendor/gems/couchrest_session_store/test/stress_test.rb create mode 100644 vendor/gems/couchrest_session_store/test/test_clock.rb create mode 100644 vendor/gems/couchrest_session_store/test/test_helper.rb diff --git a/Gemfile.lock b/Gemfile.lock index 0d18875..78f3ea2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -22,6 +22,14 @@ PATH common_languages (0.0.1) i18n +PATH + remote: vendor/gems/couchrest_session_store + specs: + couchrest_session_store (0.4.0) + actionpack (~> 4.0) + couchrest + couchrest_model + GEM remote: https://rubygems.org/ specs: diff --git a/Gemfile.orig b/Gemfile.orig deleted file mode 100644 index b7e83aa..0000000 --- a/Gemfile.orig +++ /dev/null @@ -1,119 +0,0 @@ -source 'https://rubygems.org' - -require File.expand_path('../lib/gemfile_tools.rb', __FILE__) - -## CORE -# rake 11.x throws lots of warnings about rails 3.2 code -gem "rake" -gem "rails", "~> 4.2.6" -gem "couchrest", "~> 1.1.3" -gem "couchrest_model", "~> 2.0.0" -if ARGV.grep(/assets:precompile/).empty? -<<<<<<< HEAD - gem "couchrest_session_store", "= 0.3.1" -======= - gem "couchrest_session_store", "= 0.4.0", - path: '../couchrest_session_store' ->>>>>>> upgrade: use recent gems - broken -end - -## AUTHENTICATION -gem "ruby-srp", "~> 0.2.1" -gem "rails_warden" - -## CRYPTO -# we need certificate_authority v2.0, but was never released to rubygems, -# and travis does not work well with github sources, so vendored here: -gem 'certificate_authority', :path => 'vendor/gems/certificate_authority' - -## LOCALIZATION -gem 'http_accept_language' -gem 'rails-i18n' # locale files for built-in validation messages and times - # https://github.com/svenfuchs/rails-i18n - # for a list of keys: - # https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/en.yml -gem 'common_languages', :path => 'vendor/gems/common_languages' - -## VIEWS -gem 'kaminari' -gem 'rdiscount' # for rendering .md templates - -## ASSETS -gem "jquery-rails" -gem "simple_form" -gem 'client_side_validations' -gem 'client_side_validations-simple_form' -gem "haml-rails" -gem "bootstrap-sass" -gem "sass-rails" -gem 'quiet_assets' # stops logging all the asset requests -group :production do - gem "uglifier" - gem 'therubyracer', :platforms => :ruby - # ^^ See https://github.com/sstephenson/execjs#readme - # for list of supported runtimes. -end - -## -## ENVIRONMENT SPECIFIC GEMS -## - -group :test do - # integration testing - gem 'capybara', require: false - gem 'poltergeist' # headless js - gem 'launchy' # save_and_open_page - gem 'phantomjs-binaries' # binaries specific to the os - - # moching and stubbing - gem 'mocha', :require => false - gem 'minitest-stub-const' # why? - - # generating test data - gem 'factory_girl_rails' # test data factories - gem 'faker' # names and numbers for test data - - # billing tests - gem 'fake_braintree', require: false - - # we use cucumber to document and test the api - gem 'cucumber-rails', require: false -end - -group :test, :development do - gem 'thin' - gem 'i18n-missing_translations' - gem 'pry' -end - -group :production do - gem 'SyslogLogger', '~> 2.0' -end - -group :development do - gem "better_errors" - gem "binding_of_caller" -end - -group :test, :debug do - # bundler on jessie doesn't support `:platforms => :ruby_21` - gem 'byebug' -end - -## -## OPTIONAL GEMS AND ENGINES -## - -enabled_engines.each do |name, gem_info| - gem gem_info[:name], :path => gem_info[:path], :groups => gem_info[:env] -end - -custom_gems.each do |name, gem_info| - gem gem_info[:name], :path => gem_info[:path] -end - -## -## DEPENDENCIES FOR OPTIONAL ENGINES -## - -gem 'valid_email' # used by leap_web_help diff --git a/vendor/gems/couchrest_session_store/.ruby-version b/vendor/gems/couchrest_session_store/.ruby-version new file mode 100644 index 0000000..f3a9c9a --- /dev/null +++ b/vendor/gems/couchrest_session_store/.ruby-version @@ -0,0 +1 @@ +1.9.3-p194 diff --git a/vendor/gems/couchrest_session_store/.travis.yml b/vendor/gems/couchrest_session_store/.travis.yml new file mode 100644 index 0000000..073d421 --- /dev/null +++ b/vendor/gems/couchrest_session_store/.travis.yml @@ -0,0 +1,6 @@ +services: + - couchdb +notifications: + email: false +before_script: + - "test/setup_couch.sh" diff --git a/vendor/gems/couchrest_session_store/Gemfile b/vendor/gems/couchrest_session_store/Gemfile new file mode 100644 index 0000000..88b81a0 --- /dev/null +++ b/vendor/gems/couchrest_session_store/Gemfile @@ -0,0 +1,7 @@ +source 'https://rubygems.org' + +# Specify your gem's dependencies in couchrest-session-store.gemspec +gemspec + +gem 'debugger' + diff --git a/vendor/gems/couchrest_session_store/README.md b/vendor/gems/couchrest_session_store/README.md new file mode 100644 index 0000000..60e692e --- /dev/null +++ b/vendor/gems/couchrest_session_store/README.md @@ -0,0 +1,133 @@ +# CouchRest::Session::Store # + +A simple session store based on CouchRest Model. + +## Setup ## + +`CouchRest::Session::Store` will automatically pick up the config/couch.yml +file used by CouchRest Model. + +Cleaning up sessions requires a design document in the sessions database that +enables querying by expiry. See `design/Session.json` for an example. This +design document is loaded for tests, but you will need to load it on your own +in a production environment. For example: + + curl -X PUT username:password@localhost:5984/couchrest_sessions/_design/Session --data @design/Session.json + +## Options ## + +* marshal_data: (_defaults true_) - if set to false session data will be stored + directly in the couch document. Otherwise it's marshalled and base64 encoded + to enable restoring ruby data structures. +* database: database to use combined with config prefix and suffix +* expire_after: lifetime of a session in seconds. + +## Dynamic Databases ## + +This gem also includes the module `CouchRest::Model::DatabaseMethod`, which +allow a Model to dynamically choose what database to use. + +An example of specifying database dynamically: + + class Token < CouchRest::Model::Base + include CouchRest::Model::DatabaseMethod + + use_database_method :database_name + + def self.database_name + time = Time.now.utc + "tokens_#{time.year}_#{time.month}" + end + end + +A couple notes: + +Once you include `CouchRest::Model::DatabaseMethod`, the database is no longer +automatically created. In this example, you would need to run +`Token.database.create!` or `Token.database!` in order to create the database. + +The symbol passed to `database_method` must match the name of a class method, +but if there is also an instance method with the same name then this instance +method will be called when appropriate. To state the obvious, tread lightly: +there be dragons when generating database names that depend on properties of +the instance. + +## Database Rotation ## + +The module `CouchRest::Model::Rotation` can be included in a Model in +order to use dynamic databases to perform database rotation. + +CouchDB is not good for ephemeral data because old documents are never really +deleted: when you deleted a document, it just appends a new revision. The bulk +of the old data is not stored, but it does store a record for each doc id and +revision id for the document. In the case of ephemeral data, like tokens, +sessions, or statistics, this will quickly bloat the database with a ton of +useless deleted documents. The proper solution is to rotate the databases: +create a new one regularly and delete the old one entirely. This will allow +you to recover the storage space. + +A better solution might be to just use a different database for all +ephemeral data, like MariaDB or Redis. But, if you really want to use CouchDB, this +is how you can do it. + +An example of specifying database rotation: + + class Token < CouchRest::Model::Base + include CouchRest::Model::Rotation + + rotate_database 'tokens', :every => 30.days + end + +Then, in a task triggered by a cron job: + + CouchRest::Model::Base.configure do |conf| + conf.environment = Rails.env + conf.connection_config_file = File.join(Rails.root, 'config', 'couchdb.admin.yml') + end + Token.rotate_database_now(:window => 1.day) + +Or perhaps: + + Rails.application.eager_load! + CouchRest::Model::Rotation.descendants.each do |model| + model.rotate_database_now + end + +The `:window` argument to `rotate_database_now` specifies how far in advance we +should create the new database (default 1.day). For ideal behavior, this value +should be GREATER than or equal to the frequency with which the cron job is +run. For example, if the cron job is run every hour, the argument can be +`1.hour`, `2.hours`, `1.day`, but not `20.minutes`. + +The method `rotate_database_now` will do nothing if the database has already +been rotated. Otherwise, as needed, it will create the new database, create +the design documents, set up replication between the old and new databases, +and delete the old database (once it is not used anymore). + +These actions will require admin access, so if your application normally runs +without admin rights you will need specify a different configuration for +CouchRest::Model before `rotate_database_now` is called. + +Known issues: + +* If you change the rotation period, there will be a break in the rotation + (old documents will not get replicated to the new rotated db) and the old db + will not get automatically deleted. + +* Calling `Model.database.delete!` will not necessarily remove all the + relevant databases because of the way prior and future databases are kept + for the 'window' period. + +## Changes ## + +0.3.0 + +* Added support for dynamic and rotating databases. + +0.2.4 + +* Do not crash if can't connect to CouchDB + +0.2.3 + +* Better retry and conflict catching.d \ No newline at end of file diff --git a/vendor/gems/couchrest_session_store/Rakefile b/vendor/gems/couchrest_session_store/Rakefile new file mode 100644 index 0000000..8e1dc9c --- /dev/null +++ b/vendor/gems/couchrest_session_store/Rakefile @@ -0,0 +1,9 @@ +#!/usr/bin/env rake +require "bundler/gem_tasks" +require 'rake/testtask' + +task default: [:test] + +Rake::TestTask.new do |t| + t.pattern = "test/*_test.rb" +end diff --git a/vendor/gems/couchrest_session_store/couchrest_session_store.gemspec b/vendor/gems/couchrest_session_store/couchrest_session_store.gemspec new file mode 100644 index 0000000..bf3b2b2 --- /dev/null +++ b/vendor/gems/couchrest_session_store/couchrest_session_store.gemspec @@ -0,0 +1,25 @@ +# _*_ encoding: utf-8 -*- + +Gem::Specification.new do |gem| + + gem.authors = ["Azul"] + gem.email = ["azul@leap.se"] + gem.summary = "A Rails Session Store based on CouchRest Model" + gem.description = gem.summary + gem.homepage = "http://github.com/azul/couchrest_session_store" + + gem.has_rdoc = true +# gem.extra_rdoc_files = ["LICENSE"] + + gem.files = `git ls-files`.split("\n") + gem.name = "couchrest_session_store" + gem.require_paths = ["lib"] + gem.version = '0.4.0' + + gem.add_dependency "couchrest" + gem.add_dependency "couchrest_model" + gem.add_dependency "actionpack", '~> 4.0' + + gem.add_development_dependency "minitest" + gem.add_development_dependency "rake" +end diff --git a/vendor/gems/couchrest_session_store/design/Session.json b/vendor/gems/couchrest_session_store/design/Session.json new file mode 100644 index 0000000..7020278 --- /dev/null +++ b/vendor/gems/couchrest_session_store/design/Session.json @@ -0,0 +1,8 @@ +{ + "views": { + "by_expires": { + "reduce": "_sum", + "map": "function(doc) {\n if(typeof doc.expires !== \"undefined\") {\n emit(doc.expires, 1);\n }\n}\n" + } + } +} diff --git a/vendor/gems/couchrest_session_store/lib/couchrest/session.rb b/vendor/gems/couchrest_session_store/lib/couchrest/session.rb new file mode 100644 index 0000000..430732c --- /dev/null +++ b/vendor/gems/couchrest_session_store/lib/couchrest/session.rb @@ -0,0 +1,15 @@ +module CouchRest + + class StorageMissing < Exception + attr_reader :db + def initialize(request, db) + super(request) + @db = db.name + @message = "The database '#{db}' does not exist." + end + end + + module Session + end +end + diff --git a/vendor/gems/couchrest_session_store/lib/couchrest/session/utility.rb b/vendor/gems/couchrest_session_store/lib/couchrest/session/utility.rb new file mode 100644 index 0000000..3982c28 --- /dev/null +++ b/vendor/gems/couchrest_session_store/lib/couchrest/session/utility.rb @@ -0,0 +1,12 @@ +module CouchRest::Session::Utility + module_function + + def marshal(data) + ::Base64.encode64(Marshal.dump(data)) if data + end + + def unmarshal(data) + Marshal.load(::Base64.decode64(data)) if data + end + +end diff --git a/vendor/gems/couchrest_session_store/lib/couchrest_session_store.rb b/vendor/gems/couchrest_session_store/lib/couchrest_session_store.rb new file mode 100644 index 0000000..78c6a25 --- /dev/null +++ b/vendor/gems/couchrest_session_store/lib/couchrest_session_store.rb @@ -0,0 +1,11 @@ +require 'couchrest' +require 'couchrest_model' +# ensure compatibility with couchrest_model +gem 'actionpack', '~> 4.0' +require 'action_dispatch' + +require 'couchrest/model/database_method' +require 'couchrest/model/rotation' +require 'couchrest/session' +require 'couchrest/session/store' +require 'couchrest/session/document' diff --git a/vendor/gems/couchrest_session_store/test/couch_tester.rb b/vendor/gems/couchrest_session_store/test/couch_tester.rb new file mode 100644 index 0000000..b623044 --- /dev/null +++ b/vendor/gems/couchrest_session_store/test/couch_tester.rb @@ -0,0 +1,27 @@ +# +# Access the couch directly so we can test its state without relying +# on the SessionStore +# + +class CouchTester < CouchRest::Document + include CouchRest::Model::Configuration + include CouchRest::Model::Connection + include CouchRest::Model::Rotation + + rotate_database 'sessions', + :every => 1.month, :expiration_field => :expires + + def initialize(options = {}) + end + + def get(sid) + database.get(sid) + end + + def update(sid, diff) + doc = database.get(sid) + doc.merge! diff + database.save_doc(doc) + end + +end diff --git a/vendor/gems/couchrest_session_store/test/database_rotation_test.rb b/vendor/gems/couchrest_session_store/test/database_rotation_test.rb new file mode 100644 index 0000000..856db11 --- /dev/null +++ b/vendor/gems/couchrest_session_store/test/database_rotation_test.rb @@ -0,0 +1,88 @@ +require_relative 'test_helper' + +class RotationTest < MiniTest::Test + + class Token < CouchRest::Model::Base + include CouchRest::Model::Rotation + property :token, String + rotate_database 'test_rotate', :every => 1.day + end + + TEST_DB_RE = /test_rotate_\d+/ + + def test_rotate + delete_all_dbs + doc = nil + original_name = nil + next_db_name = nil + + Time.stub :now, Time.gm(2015,3,7,0) do + Token.create_database! + doc = Token.create!(:token => 'aaaa') + original_name = Token.rotated_database_name + assert database_exists?(original_name) + assert_equal 1, count_dbs + end + + # do nothing yet + Time.stub :now, Time.gm(2015,3,7,22) do + Token.rotate_database_now(:window => 1.hour) + assert_equal original_name, Token.rotated_database_name + assert_equal 1, count_dbs + end + + # create next db, but don't switch yet. + Time.stub :now, Time.gm(2015,3,7,23) do + Token.rotate_database_now(:window => 1.hour) + assert_equal 2, count_dbs + next_db_name = Token.rotated_database_name(Time.gm(2015,3,8)) + assert original_name != next_db_name + assert database_exists?(next_db_name) + sleep 0.2 # allow time for documents to replicate + assert_equal( + Token.get(doc.id).token, + Token.get(doc.id, database(next_db_name)).token + ) + end + + # use next db + Time.stub :now, Time.gm(2015,3,8) do + Token.rotate_database_now(:window => 1.hour) + assert_equal 2, count_dbs + assert_equal next_db_name, Token.rotated_database_name + token = Token.get(doc.id) + token.update_attributes(:token => 'bbbb') + assert_equal 'bbbb', Token.get(doc.id).token + assert_equal 'aaaa', Token.get(doc.id, database(original_name)).token + end + + # delete prior db + Time.stub :now, Time.gm(2015,3,8,1) do + Token.rotate_database_now(:window => 1.hour) + assert_equal 1, count_dbs + end + end + + private + + def database(db_name) + Token.server.database(Token.db_name_with_prefix(db_name)) + end + + def database_exists?(dbname) + Token.database_exists?(dbname) + end + + def delete_all_dbs(regexp=TEST_DB_RE) + Token.server.databases.each do |db| + if regexp.match(db) + Token.server.database(db).delete! + end + end + end + + def count_dbs(regexp=TEST_DB_RE) + Token.server.databases.grep(regexp).count + end + +end diff --git a/vendor/gems/couchrest_session_store/test/session_document_test.rb b/vendor/gems/couchrest_session_store/test/session_document_test.rb new file mode 100644 index 0000000..2125d10 --- /dev/null +++ b/vendor/gems/couchrest_session_store/test/session_document_test.rb @@ -0,0 +1,27 @@ +require File.expand_path(File.dirname(__FILE__) + '/test_helper') + +class SessionDocumentTest < MiniTest::Test + + def test_storing_session + sid = '1234' + session = {'a' => 'b'} + options = {} + doc = CouchRest::Session::Document.build_or_update(sid, session, options) + doc.save + doc.fetch(sid) + assert_equal session, doc.to_session + end + + def test_storing_session_with_conflict + sid = '1234' + session = {'a' => 'b'} + options = {} + doc = CouchRest::Session::Document.build_or_update(sid, session, options) + doc2 = CouchRest::Session::Document.build_or_update(sid, session, options) + doc.save + doc2.save + doc2.fetch(sid) + assert_equal session, doc2.to_session + end + +end diff --git a/vendor/gems/couchrest_session_store/test/setup_couch.sh b/vendor/gems/couchrest_session_store/test/setup_couch.sh new file mode 100755 index 0000000..731534b --- /dev/null +++ b/vendor/gems/couchrest_session_store/test/setup_couch.sh @@ -0,0 +1,7 @@ +HOST="http://localhost:5984" +echo "couch version :" +curl -X GET $HOST + +curl -X PUT $HOST/couchrest_sessions +curl -X PUT $HOST/couchrest_sessions/_design/Session --data @design/Session.json + diff --git a/vendor/gems/couchrest_session_store/test/stress_test.rb b/vendor/gems/couchrest_session_store/test/stress_test.rb new file mode 100644 index 0000000..b74b132 --- /dev/null +++ b/vendor/gems/couchrest_session_store/test/stress_test.rb @@ -0,0 +1,51 @@ +require_relative 'test_helper' + +# +# This doesn't really test much, but is useful if you want to see what happens +# when you have a lot of documents. +# + +class StressTest < MiniTest::Test + + COUNT = 200 # change to 200,000 if you dare + + class Stress < CouchRest::Model::Base + include CouchRest::Model::Rotation + property :token, String + property :expires_at, Time + rotate_database 'stress_test', :every => 1.day, :expiration_field => :expires_at + end + + def test_stress + delete_all_dbs /^couchrest_stress_test_\d+$/ + + Stress.database! + COUNT.times do |i| + doc = Stress.create!(:token => SecureRandom.hex(32), :expires_at => expires(i)) + end + + Time.stub :now, 1.day.from_now do + Stress.rotate_database_now(:window => 1.hour) + sleep 0.5 + assert_equal (COUNT/100)+1, Stress.database.info["doc_count"] + end + end + + private + + def delete_all_dbs(regexp=TEST_DB_RE) + Stress.server.databases.each do |db| + if regexp.match(db) + Stress.server.database(db).delete! + end + end + end + + def expires(i) + if i % 100 == 0 + 1.hour.from_now.utc + else + 1.hour.ago.utc + end + end +end diff --git a/vendor/gems/couchrest_session_store/test/test_clock.rb b/vendor/gems/couchrest_session_store/test/test_clock.rb new file mode 100644 index 0000000..4170763 --- /dev/null +++ b/vendor/gems/couchrest_session_store/test/test_clock.rb @@ -0,0 +1,12 @@ +class TestClock + attr_accessor :now + + def initialize(tick = 60) + @tick = tick + @now = Time.now + end + + def tick(seconds = nil) + @now += seconds || @tick + end +end diff --git a/vendor/gems/couchrest_session_store/test/test_helper.rb b/vendor/gems/couchrest_session_store/test/test_helper.rb new file mode 100644 index 0000000..32f147d --- /dev/null +++ b/vendor/gems/couchrest_session_store/test/test_helper.rb @@ -0,0 +1,9 @@ +require "rubygems" +gem 'minitest' +require 'minitest/autorun' +require File.expand_path(File.dirname(__FILE__) + '/../lib/couchrest_session_store.rb') +require File.expand_path(File.dirname(__FILE__) + '/couch_tester.rb') +require File.expand_path(File.dirname(__FILE__) + '/test_clock.rb') + +# Create the session db if it does not already exist. +CouchRest::Session::Document.create_database! -- cgit v1.2.3 From 9a8f1da14f6a0ab83206c57059fbc8cf5bc77b60 Mon Sep 17 00:00:00 2001 From: Azul Date: Wed, 23 Mar 2016 22:19:27 +0100 Subject: upgrade: no more underspecified match routes --- config/routes.rb | 4 ++-- engines/billing/config/routes.rb | 33 +++++++++++++++------------------ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index e370aa4..be3b3be 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -10,8 +10,8 @@ LeapWeb::Application.routes.draw do # HTTP Error Handling # instead of the default error pages use the errors controller and views # - match '/404' => 'errors#not_found' - match '/500' => 'errors#server_error' + match '/404' => 'errors#not_found', via: [:get, :post] + match '/500' => 'errors#server_error', via: [:get, :post] scope "(:locale)", :locale => CommonLanguages.match_available, :controller => 'pages', :action => 'show' do get 'privacy-policy', :as => 'privacy_policy' diff --git a/engines/billing/config/routes.rb b/engines/billing/config/routes.rb index 357c55b..12a6778 100644 --- a/engines/billing/config/routes.rb +++ b/engines/billing/config/routes.rb @@ -2,26 +2,23 @@ Rails.application.routes.draw do scope "(:locale)", :locale => CommonLanguages.match_available do - get 'payments/new' => 'payments#new', :as => :new_payment - post 'payments/confirm' => 'payments#confirm', :as => :confirm_payment - # match 'payments/new' => 'payments#new', :as => :new_payment - # match 'payments/confirm' => 'payments#confirm', :as => :confirm_payment - #resources :users do - # resources :payments, :only => [:new, :confirm] - # resources :subscriptions, :only => [:index, :destroy] - #end - resources :subscriptions, :only => [:index, :show] do - member do - post 'subscribe' - delete 'unsubscribe' + get 'payments/new' => 'payments#new', :as => :new_payment + post 'payments/confirm' => 'payments#confirm', :as => :confirm_payment + # match 'payments/new' => 'payments#new', :as => :new_payment + # match 'payments/confirm' => 'payments#confirm', :as => :confirm_payment + #resources :users do + # resources :payments, :only => [:new, :confirm] + # resources :subscriptions, :only => [:index, :destroy] + #end + resources :subscriptions, :only => [:index, :show] do + member do + post 'subscribe' + delete 'unsubscribe' + end end - end - - resources :customer, :only => [:new, :edit] - match 'customer/confirm/' => 'customer#confirm', :as => :confirm_customer - match 'customer/show/:id' => 'customer#show', :as => :show_customer + resources :customer, :only => [:new, :edit] - match 'billing_admin' => 'billing_admin#show', :as => :billing_admin + get 'billing_admin' => 'billing_admin#show' end end -- cgit v1.2.3 From c7ef6adcd20e9ac9ca729a3ee2a718d31fbb6b51 Mon Sep 17 00:00:00 2001 From: Azul Date: Wed, 23 Mar 2016 22:46:06 +0100 Subject: upgrade: add responders gem as a stopgap meassure respond_with is discouraged. --- Gemfile | 2 ++ Gemfile.lock | 3 +++ 2 files changed, 5 insertions(+) diff --git a/Gemfile b/Gemfile index 071dd3c..bf05642 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,8 @@ require File.expand_path('../lib/gemfile_tools.rb', __FILE__) # rake 11.x throws lots of warnings about rails 3.2 code gem "rake" gem "rails", "~> 4.2.6" +# TODO: drop this and the respond_with usage +gem 'responders', '~> 2.0' gem "couchrest", "~> 2.0.0.rc3" gem "couchrest_model", "~> 2.1.0.beta2" if ARGV.grep(/assets:precompile/).empty? diff --git a/Gemfile.lock b/Gemfile.lock index 78f3ea2..cf005f3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -253,6 +253,8 @@ GEM rdiscount (2.1.8) ref (2.0.0) regexp_parser (0.3.3) + responders (2.1.2) + railties (>= 4.2.0, < 5.1) ruby-srp (0.2.1) ruby_parser (3.8.1) sexp_processor (~> 4.1) @@ -346,6 +348,7 @@ DEPENDENCIES rails_warden rake rdiscount + responders (~> 2.0) ruby-srp (~> 0.2.1) sass-rails simple_form -- cgit v1.2.3 From 52a6dc82305f0268684ceb10557773b862bc611c Mon Sep 17 00:00:00 2001 From: Azul Date: Thu, 24 Mar 2016 08:54:38 +0100 Subject: fix browser_integration_test we need to require 'capybara/rails' so that Capybara::DSL is available. ActionController::RecordIdentifier was moved to ActionView --- test/performance/browsing_test.rb | 12 ------------ test/support/browser_integration_test.rb | 3 ++- 2 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 test/performance/browsing_test.rb diff --git a/test/performance/browsing_test.rb b/test/performance/browsing_test.rb deleted file mode 100644 index 3fea27b..0000000 --- a/test/performance/browsing_test.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'test_helper' -require 'rails/performance_test_help' - -class BrowsingTest < ActionDispatch::PerformanceTest - # Refer to the documentation for all available options - # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory] - # :output => 'tmp/performance', :formats => [:flat] } - - def test_homepage - get '/' - end -end diff --git a/test/support/browser_integration_test.rb b/test/support/browser_integration_test.rb index 1deb8fa..5455fba 100644 --- a/test/support/browser_integration_test.rb +++ b/test/support/browser_integration_test.rb @@ -3,10 +3,11 @@ # # Use this class for capybara based integration tests for the ui. # +require 'capybara/rails' class BrowserIntegrationTest < ActionDispatch::IntegrationTest # let's use dom_id inorder to identify sections - include ActionController::RecordIdentifier + include ActionView::RecordIdentifier CONFIG_RU = (Rails.root + 'config.ru').to_s OUTER_APP = Rack::Builder.parse_file(CONFIG_RU).first -- cgit v1.2.3 From 0ac511a31a6652ab00bbc765079b1c56128b191f Mon Sep 17 00:00:00 2001 From: Azul Date: Thu, 24 Mar 2016 09:03:30 +0100 Subject: split up integration account test AccountLivecycleTest -> CRUD accounts SecurityTest -> security specific tests AdminTest -> admin specific tests --- test/integration/browser/account_livecycle_test.rb | 114 +++++++++++++ test/integration/browser/account_test.rb | 176 --------------------- test/integration/browser/admin_test.rb | 18 +++ test/integration/browser/security_test.rb | 52 ++++++ 4 files changed, 184 insertions(+), 176 deletions(-) create mode 100644 test/integration/browser/account_livecycle_test.rb delete mode 100644 test/integration/browser/account_test.rb create mode 100644 test/integration/browser/security_test.rb diff --git a/test/integration/browser/account_livecycle_test.rb b/test/integration/browser/account_livecycle_test.rb new file mode 100644 index 0000000..604f456 --- /dev/null +++ b/test/integration/browser/account_livecycle_test.rb @@ -0,0 +1,114 @@ +require 'test_helper' + +class AccountLivecycleTest < BrowserIntegrationTest + + teardown do + Identity.destroy_all_orphaned + end + + test "signup successfully when invited" do + username, password = submit_signup + assert page.has_content?("Welcome #{username}") + click_on 'Log Out' + assert page.has_content?("Log In") + assert_equal '/', current_path + assert user = User.find_by_login(username) + user.account.destroy + end + + test "signup successfully without invitation" do + with_config invite_required: false do + + username ||= "test_#{SecureRandom.urlsafe_base64}".downcase + password ||= SecureRandom.base64 + + visit '/users/new' + fill_in 'Username', with: username + fill_in 'Password', with: password + fill_in 'Password confirmation', with: password + click_on 'Sign Up' + + assert page.has_content?("Welcome #{username}") + end + end + + test "signup with username ending in dot json" do + username = Faker::Internet.user_name + '.json' + submit_signup username + assert page.has_content?("Welcome #{username}") + end + + test "signup with reserved username" do + username = 'certmaster' + submit_signup username + assert page.has_content?("is reserved.") + end + + test "successful login" do + username, password = submit_signup + click_on 'Log Out' + attempt_login(username, password) + assert page.has_content?("Welcome #{username}") + within('.sidenav li.active') do + assert page.has_content?("Overview") + end + User.find_by_login(username).account.destroy + end + + test "failed login" do + visit '/' + attempt_login("username", "wrong password") + assert_invalid_login(page) + end + + test "account destruction" do + username, password = submit_signup + + click_on I18n.t('account_settings') + click_on I18n.t('destroy_my_account') + assert page.has_content?(I18n.t('account_destroyed')) + assert_equal 1, Identity.by_address.key("#{username}@test.me").count + attempt_login(username, password) + assert_invalid_login(page) + end + + test "handle blocked after account destruction" do + username, password = submit_signup + click_on I18n.t('account_settings') + click_on I18n.t('destroy_my_account') + submit_signup(username) + assert page.has_content?('has already been taken') + end + + test "change pgp key" do + with_config user_actions: ['change_pgp_key'] do + pgp_key = FactoryGirl.build :pgp_key + login + click_on "Account Settings" + within('#update_pgp_key') do + fill_in 'Public key', with: pgp_key + click_on 'Save' + end + page.assert_selector 'input[value="Saving..."]' + # at some point we're done: + page.assert_no_selector 'input[value="Saving..."]' + assert page.has_field? 'Public key', with: pgp_key.to_s + @user.reload + assert_equal pgp_key, @user.public_key + end + end + + def attempt_login(username, password) + click_on 'Log In' + fill_in 'Username', with: username + fill_in 'Password', with: password + click_on 'Log In' + end + + def assert_invalid_login(page) + assert page.has_selector? '.btn-primary.disabled' + assert page.has_content? I18n.t(:invalid_user_pass) + assert page.has_no_selector? '.btn-primary.disabled' + end + +end diff --git a/test/integration/browser/account_test.rb b/test/integration/browser/account_test.rb deleted file mode 100644 index 50adb23..0000000 --- a/test/integration/browser/account_test.rb +++ /dev/null @@ -1,176 +0,0 @@ -require 'test_helper' - -class AccountTest < BrowserIntegrationTest - - teardown do - Identity.destroy_all_orphaned - end - - test "signup successfully when invited" do - username, password = submit_signup - assert page.has_content?("Welcome #{username}") - click_on 'Log Out' - assert page.has_content?("Log In") - assert_equal '/', current_path - assert user = User.find_by_login(username) - user.account.destroy - end - - test "signup successfully without invitation" do - with_config invite_required: false do - - username ||= "test_#{SecureRandom.urlsafe_base64}".downcase - password ||= SecureRandom.base64 - - visit '/users/new' - fill_in 'Username', with: username - fill_in 'Password', with: password - fill_in 'Password confirmation', with: password - click_on 'Sign Up' - - assert page.has_content?("Welcome #{username}") - end - end - - test "signup with username ending in dot json" do - username = Faker::Internet.user_name + '.json' - submit_signup username - assert page.has_content?("Welcome #{username}") - end - - test "signup with reserved username" do - username = 'certmaster' - submit_signup username - assert page.has_content?("is reserved.") - end - - test "successful login" do - username, password = submit_signup - click_on 'Log Out' - attempt_login(username, password) - assert page.has_content?("Welcome #{username}") - within('.sidenav li.active') do - assert page.has_content?("Overview") - end - User.find_by_login(username).account.destroy - end - - test "failed login" do - visit '/' - attempt_login("username", "wrong password") - assert_invalid_login(page) - end - - test "account destruction" do - username, password = submit_signup - - click_on I18n.t('account_settings') - click_on I18n.t('destroy_my_account') - assert page.has_content?(I18n.t('account_destroyed')) - assert_equal 1, Identity.by_address.key("#{username}@test.me").count - attempt_login(username, password) - assert_invalid_login(page) - end - - test "handle blocked after account destruction" do - username, password = submit_signup - click_on I18n.t('account_settings') - click_on I18n.t('destroy_my_account') - submit_signup(username) - assert page.has_content?('has already been taken') - end - - test "default user actions" do - login - click_on "Account Settings" - assert page.has_content? I18n.t('destroy_my_account') - assert page.has_no_css? '#update_login_and_password' - assert page.has_no_css? '#update_pgp_key' - end - - test "default admin actions" do - login - with_config admins: [@user.login] do - click_on "Account Settings" - assert page.has_content? I18n.t('destroy_my_account') - assert page.has_no_css? '#update_login_and_password' - assert page.has_css? '#update_pgp_key' - end - end - - test "change pgp key" do - with_config user_actions: ['change_pgp_key'] do - pgp_key = FactoryGirl.build :pgp_key - login - click_on "Account Settings" - within('#update_pgp_key') do - fill_in 'Public key', with: pgp_key - click_on 'Save' - end - page.assert_selector 'input[value="Saving..."]' - # at some point we're done: - page.assert_no_selector 'input[value="Saving..."]' - assert page.has_field? 'Public key', with: pgp_key.to_s - @user.reload - assert_equal pgp_key, @user.public_key - end - end - - - # trying to seed an invalid A for srp login - test "detects attempt to circumvent SRP" do - InviteCodeValidator.any_instance.stubs(:validate) - - user = FactoryGirl.create :user - visit '/login' - fill_in 'Username', with: user.login - fill_in 'Password', with: "password" - inject_malicious_js - click_on 'Log In' - assert page.has_content?("Invalid random key") - assert page.has_no_content?("Welcome") - user.destroy - end - - test "reports internal server errors" do - V1::UsersController.any_instance.stubs(:create).raises - submit_signup - assert page.has_content?("server failed") - end - - test "does not render signup form without js" do - Capybara.current_driver = :rack_test # no js - visit '/signup' - assert page.has_no_content?("Username") - assert page.has_no_content?("Password") - end - - test "does not render login form without js" do - Capybara.current_driver = :rack_test # no js - visit '/login' - assert page.has_no_content?("Username") - assert page.has_no_content?("Password") - end - - def attempt_login(username, password) - click_on 'Log In' - fill_in 'Username', with: username - fill_in 'Password', with: password - click_on 'Log In' - end - - def assert_invalid_login(page) - assert page.has_selector? '.btn-primary.disabled' - assert page.has_content? I18n.t(:invalid_user_pass) - assert page.has_no_selector? '.btn-primary.disabled' - end - - def inject_malicious_js - page.execute_script <<-EOJS - var calc = new srp.Calculate(); - calc.A = function(_a) {return "00";}; - calc.S = calc.A; - srp.session = new srp.Session(null, calc); - EOJS - end -end diff --git a/test/integration/browser/admin_test.rb b/test/integration/browser/admin_test.rb index 902c981..0b43c29 100644 --- a/test/integration/browser/admin_test.rb +++ b/test/integration/browser/admin_test.rb @@ -2,6 +2,24 @@ require 'test_helper' class AdminTest < BrowserIntegrationTest + test "default user actions" do + login + click_on "Account Settings" + assert page.has_content? I18n.t('destroy_my_account') + assert page.has_no_css? '#update_login_and_password' + assert page.has_no_css? '#update_pgp_key' + end + + test "default admin actions" do + login + with_config admins: [@user.login] do + click_on "Account Settings" + assert page.has_content? I18n.t('destroy_my_account') + assert page.has_no_css? '#update_login_and_password' + assert page.has_css? '#update_pgp_key' + end + end + test "clear blocked handle" do id = FactoryGirl.create :identity submit_signup(id.login) diff --git a/test/integration/browser/security_test.rb b/test/integration/browser/security_test.rb new file mode 100644 index 0000000..c13acd8 --- /dev/null +++ b/test/integration/browser/security_test.rb @@ -0,0 +1,52 @@ +require 'test_helper' + +class SecurityTest < BrowserIntegrationTest + + teardown do + Identity.destroy_all_orphaned + end + + # trying to seed an invalid A for srp login + test "detects attempt to circumvent SRP" do + InviteCodeValidator.any_instance.stubs(:validate) + + user = FactoryGirl.create :user + visit '/login' + fill_in 'Username', with: user.login + fill_in 'Password', with: "password" + inject_malicious_js + click_on 'Log In' + assert page.has_content?("Invalid random key") + assert page.has_no_content?("Welcome") + user.destroy + end + + test "reports internal server errors" do + V1::UsersController.any_instance.stubs(:create).raises + submit_signup + assert page.has_content?("server failed") + end + + test "does not render signup form without js" do + Capybara.current_driver = :rack_test # no js + visit '/signup' + assert page.has_no_content?("Username") + assert page.has_no_content?("Password") + end + + test "does not render login form without js" do + Capybara.current_driver = :rack_test # no js + visit '/login' + assert page.has_no_content?("Username") + assert page.has_no_content?("Password") + end + + def inject_malicious_js + page.execute_script <<-EOJS + var calc = new srp.Calculate(); + calc.A = function(_a) {return "00";}; + calc.S = calc.A; + srp.session = new srp.Session(null, calc); + EOJS + end +end -- cgit v1.2.3 From 6d9bd6b966ec2370b7f8659b0810b03c5d1568aa Mon Sep 17 00:00:00 2001 From: Azul Date: Thu, 24 Mar 2016 09:08:46 +0100 Subject: upgrade: unique test names Rails 4.2 runs all tests mixed together. So unit tests and integration tests may not have conflicting names. --- test/integration/api/token_auth_test.rb | 16 ++++++++++++++++ test/integration/api/token_test.rb | 16 ---------------- test/unit/temporary_user_test.rb | 33 +++++++++++++++++++++++++++++++++ test/unit/tmp_user_test.rb | 33 --------------------------------- 4 files changed, 49 insertions(+), 49 deletions(-) create mode 100644 test/integration/api/token_auth_test.rb delete mode 100644 test/integration/api/token_test.rb create mode 100644 test/unit/temporary_user_test.rb delete mode 100644 test/unit/tmp_user_test.rb diff --git a/test/integration/api/token_auth_test.rb b/test/integration/api/token_auth_test.rb new file mode 100644 index 0000000..3b83f23 --- /dev/null +++ b/test/integration/api/token_auth_test.rb @@ -0,0 +1,16 @@ +require_relative '../../test_helper' +require_relative 'srp_test' + +class TokenAuthTest < SrpTest + + setup do + register_user + end + + test "stores token SHA512 encoded" do + authenticate + token = server_auth['token'] + assert Token.find(Digest::SHA512.hexdigest(token)) + end + +end diff --git a/test/integration/api/token_test.rb b/test/integration/api/token_test.rb deleted file mode 100644 index dafbfb7..0000000 --- a/test/integration/api/token_test.rb +++ /dev/null @@ -1,16 +0,0 @@ -require_relative '../../test_helper' -require_relative 'srp_test' - -class TokenTest < SrpTest - - setup do - register_user - end - - test "stores token SHA512 encoded" do - authenticate - token = server_auth['token'] - assert Token.find(Digest::SHA512.hexdigest(token)) - end - -end diff --git a/test/unit/temporary_user_test.rb b/test/unit/temporary_user_test.rb new file mode 100644 index 0000000..38ccd67 --- /dev/null +++ b/test/unit/temporary_user_test.rb @@ -0,0 +1,33 @@ +require 'test_helper' + +class TemporaryUserTest < ActiveSupport::TestCase + + setup do + InviteCodeValidator.any_instance.stubs(:validate) + end + + test "tmp_user saved to tmp_users" do + begin + assert User.ancestors.include?(TemporaryUser) + + assert_difference('User.database.info["doc_count"]') do + normal_user = User.create!(:login => 'a'+SecureRandom.hex(5).downcase, + :password_verifier => 'ABCDEF0010101', :password_salt => 'ABCDEF') + refute normal_user.database.to_s.include?('tmp') + end + + assert_difference('User.tmp_database.info["doc_count"]') do + tmp_user = User.create!(:login => 'tmp_user_'+SecureRandom.hex(5).downcase, + :password_verifier => 'ABCDEF0010101', :password_salt => 'ABCDEF') + assert tmp_user.database.to_s.include?('tmp') + end + ensure + begin + normal_user.destroy + tmp_user.destroy + rescue + end + end + end + +end diff --git a/test/unit/tmp_user_test.rb b/test/unit/tmp_user_test.rb deleted file mode 100644 index 1dea5f9..0000000 --- a/test/unit/tmp_user_test.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'test_helper' - -class TmpUserTest < ActiveSupport::TestCase - - setup do - InviteCodeValidator.any_instance.stubs(:validate) - end - - test "tmp_user saved to tmp_users" do - begin - assert User.ancestors.include?(TemporaryUser) - - assert_difference('User.database.info["doc_count"]') do - normal_user = User.create!(:login => 'a'+SecureRandom.hex(5).downcase, - :password_verifier => 'ABCDEF0010101', :password_salt => 'ABCDEF') - refute normal_user.database.to_s.include?('tmp') - end - - assert_difference('User.tmp_database.info["doc_count"]') do - tmp_user = User.create!(:login => 'tmp_user_'+SecureRandom.hex(5).downcase, - :password_verifier => 'ABCDEF0010101', :password_salt => 'ABCDEF') - assert tmp_user.database.to_s.include?('tmp') - end - ensure - begin - normal_user.destroy - tmp_user.destroy - rescue - end - end - end - -end -- cgit v1.2.3 From 96912fcda221b1403654c0770b227bbf13c9ba51 Mon Sep 17 00:00:00 2001 From: Azul Date: Thu, 24 Mar 2016 09:34:27 +0100 Subject: upgrade: add binstubs to git http://www.scimedsolutions.com/articles/43-the-new-way-binstubs-work The new wisdom is to also use binstubs in production. Also updated .gitignore according to http://railsdiff.org/3.2.22.2/4.2.6 Removed .swp ignore as that is editor specific and should be set per dev system rather than per project. --- .gitignore | 7 +++++-- bin/bundle | 3 +++ bin/rails | 4 ++++ bin/rake | 4 ++++ bin/setup | 29 +++++++++++++++++++++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) create mode 100755 bin/bundle create mode 100755 bin/rails create mode 100755 bin/rake create mode 100755 bin/setup diff --git a/.gitignore b/.gitignore index 3aa8fc7..8d49deb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,13 @@ +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + # Ignore bundler config /.bundle -bin # Ignore the default SQLite database. /db/*.sqlite3 +/db/*.sqlite3-journal # Ignore all logfiles and tempfiles. /log/*.log @@ -12,7 +16,6 @@ bin /pkg /*/pkg /log -.*.swp */Gemfile.lock test/dummy/log/* test/dummy/tmp/* diff --git a/bin/bundle b/bin/bundle new file mode 100755 index 0000000..66e9889 --- /dev/null +++ b/bin/bundle @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +load Gem.bin_path('bundler', 'bundle') diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..5191e69 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path('../../config/application', __FILE__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..1724048 --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative '../config/boot' +require 'rake' +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..acdb2c1 --- /dev/null +++ b/bin/setup @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +require 'pathname' + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) + +Dir.chdir APP_ROOT do + # This script is a starting point to setup your application. + # Add necessary setup steps to this file: + + puts "== Installing dependencies ==" + system "gem install bundler --conservative" + system "bundle check || bundle install" + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # system "cp config/database.yml.sample config/database.yml" + # end + + puts "\n== Preparing database ==" + system "bin/rake db:setup" + + puts "\n== Removing old logs and tempfiles ==" + system "rm -f log/*" + system "rm -rf tmp/cache" + + puts "\n== Restarting application server ==" + system "touch tmp/restart.txt" +end -- cgit v1.2.3 From cb58e83c3525917da381bd43773fc2c3c40811ea Mon Sep 17 00:00:00 2001 From: Azul Date: Thu, 24 Mar 2016 09:41:53 +0100 Subject: upgrade: environments/test.rb Changed according to http://railsdiff.org/3.2.22.2/4.2.6 Should also get rid of some warnings. --- config/environments/test.rb | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/config/environments/test.rb b/config/environments/test.rb index 1a38df7..8ed23ed 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,5 +1,5 @@ -LeapWeb::Application.configure do - # Settings specified here will take precedence over those in config/application.rb +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that @@ -7,29 +7,36 @@ LeapWeb::Application.configure do # and recreated between test runs. Don't rely on the data there! config.cache_classes = true - # Configure static asset server for tests with Cache-Control for performance - config.serve_static_assets = true - config.static_cache_control = "public, max-age=3600" + # Do not eager load code on boot. This avoids loading your whole application + # just for the purpose of running a single test. If you are using a tool that + # preloads Rails for running tests, you may have to set it to true. + config.eager_load = false - # Log error messages when you accidentally call methods on nil - config.whiny_nils = true + # Configure static asset server for tests with Cache-Control for performance + config.serve_static_files = true + config.static_cache_control = 'public, max-age=3600' - # Show full error reports and disable caching + # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false - # Raise exceptions instead of rendering exception templates + # Raise exceptions instead of rendering exception templates. config.action_dispatch.show_exceptions = false - # Disable request forgery protection in test environment - config.action_controller.allow_forgery_protection = false + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test + # Randomize the order test cases are executed. + config.active_support.test_order = :random - # Print deprecation notices to the stderr + # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true end -- cgit v1.2.3 From 4b16c4ff2220a42a27a19230785461c6dcb74652 Mon Sep 17 00:00:00 2001 From: Azul Date: Thu, 24 Mar 2016 09:50:53 +0100 Subject: upgrade: environments:development Changed according to http://railsdiff.org/3.2.22.2/4.2.6 Also separated settings we added from those that rails has by default. --- config/environments/development.rb | 48 +++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index 3c0ff0f..4112c6d 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,38 +1,58 @@ -LeapWeb::Application.configure do - # Settings specified here will take precedence over those in config/application.rb +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + ## + # DEFAULT: + # + # rails default settings in their natural order + ## # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false - # Log error messages when you accidentally call methods on nil. - config.whiny_nils = true + # Do not eager load code on boot. + config.eager_load = false - # Show full error reports and disable caching + # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false - # Don't care if the mailer can't send + # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false - # Print deprecation notices to the Rails logger + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log - # Only use best-standards-support built into browsers - config.action_dispatch.best_standards_support = :builtin + # Debug mode disables concatenation and preprocessing of assets. + # This option may cause significant delays in view rendering with a large + # number of complex assets. + config.assets.debug = true - # Enable locale fallbacks for I18n (makes lookups for any locale fall back to - # the I18n.default_locale when a translation can not be found) - config.i18n.fallbacks = true + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. + config.assets.digest = true - # Do not compress assets - config.assets.compress = false + # Adds additional error checking when serving assets at runtime. + # Checks for improperly declared sprockets dependencies. + # Raises helpful error messages. + config.assets.raise_runtime_errors = true # If set to true, each asset file is loaded separately. If you are not # debugging js or css, it is much faster to set this to false. config.assets.debug = false + ## + # CUSTOM: + # + # our own settings + ## + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation can not be found) + config.i18n.fallbacks = true + # super hacky, but otherwise getting certificate error, and doesn't seem dangerous in development mode: OpenSSL::SSL.send(:remove_const, "VERIFY_PEER") OpenSSL::SSL.const_set("VERIFY_PEER", OpenSSL::SSL::VERIFY_NONE) -- cgit v1.2.3 From 464c2b463522cdb5e4577b1b9ab7ffb890788d94 Mon Sep 17 00:00:00 2001 From: Azul Date: Thu, 24 Mar 2016 11:00:06 +0100 Subject: upgrade: environments:production Changed according to http://railsdiff.org/3.2.22.2/4.2.6 Includes setting logging to debug. Not sure if we want this. I agree that it's good to have all info available in case something breaks. --- config/environments/production.rb | 70 ++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/config/environments/production.rb b/config/environments/production.rb index 7acca75..acdfc1d 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,37 +1,56 @@ -LeapWeb::Application.configure do - # Settings specified here will take precedence over those in config/application.rb +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. - # Code is not reloaded between requests + # Code is not reloaded between requests. config.cache_classes = true - # Full error reports are disabled and caching is turned on + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. config.consider_all_requests_local = false config.action_controller.perform_caching = true - # Disable Rails's static asset server (Apache or nginx will already do this) - config.serve_static_assets = false - # Compress JavaScripts and CSS - config.assets.compress = true + # Dble Rack::Cache to put a simple HTTP cache in front of your application + # Add `rack-cache` to your Gemfile before enabling this. + # For large-scale production use, consider using a caching reverse proxy like + # NGINX, varnish or squid. + # config.action_dispatch.rack_cache = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? + + # Compress JavaScripts and CSS. + config.assets.js_compressor = :uglifier + # config.assets.css_compressor = :sass - # Don't fallback to assets pipeline if a precompiled asset is missed + #Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # Generate digests for assets URLs + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. config.assets.digest = true - # Defaults to nil and saved in location specified by config.assets.prefix - # config.assets.manifest = YOUR_PATH + # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb - # Specifies the header that your server uses for sending files - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. config.force_ssl = APP_CONFIG[:force_ssl] - # See everything in the log (default is :info) - # config.log_level = :debug + # Use the lowest log level to ensure availability of diagnostic information + # when problems arise. + config.log_level = :debug + + # Prepend all log lines with the following tags. + # config.log_tags = [ :subdomain, :uuid ] # Use syslog if no file has been specified if APP_CONFIG[:logfile].blank? @@ -39,26 +58,23 @@ LeapWeb::Application.configure do config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new('webapp')) end - # Use a different cache store in production + # Use a different cache store in production. # config.cache_store = :mem_cache_store - # Enable serving of images, stylesheets, and JavaScripts from an asset server + # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.action_controller.asset_host = "http://assets.example.com" - # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) - # config.assets.precompile += %w( search.js ) - - # Disable delivery errors, bad email addresses will be ignored + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false - # Enable threaded mode - # config.threadsafe! - # Enable locale fallbacks for I18n (makes lookups for any locale fall back to - # the I18n.default_locale when a translation can not be found) + # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true # Send deprecation notices to registered listeners config.active_support.deprecation = :notify + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new end -- cgit v1.2.3 From 54661746ffa9f113c6b489a4d5ba170a27874ad1 Mon Sep 17 00:00:00 2001 From: Azul Date: Thu, 24 Mar 2016 11:10:48 +0100 Subject: upgrade: migrate config environment.rb boot.rb application.rb -> adopted according to http://railsdiff.org/3.2.22.2/4.2.6 Also dropped quite_assets - not sure if this is still needed with rails 4.2. If it is we can bring it back. --- Gemfile | 1 - Gemfile.lock | 3 --- config/application.rb | 57 +++++++-------------------------------------------- config/boot.rb | 5 +---- config/environment.rb | 6 +++--- 5 files changed, 11 insertions(+), 61 deletions(-) diff --git a/Gemfile b/Gemfile index bf05642..0df9357 100644 --- a/Gemfile +++ b/Gemfile @@ -43,7 +43,6 @@ gem 'client_side_validations-simple_form' gem "haml-rails" gem "bootstrap-sass" gem "sass-rails" -gem 'quiet_assets' # stops logging all the asset requests group :production do gem "uglifier" gem 'therubyracer', :platforms => :ruby diff --git a/Gemfile.lock b/Gemfile.lock index cf005f3..bd41a09 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -213,8 +213,6 @@ GEM coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - quiet_assets (1.1.0) - railties (>= 3.1, < 5.0) rack (1.6.4) rack-protection (1.5.3) rack @@ -342,7 +340,6 @@ DEPENDENCIES phantomjs-binaries poltergeist pry - quiet_assets rails (~> 4.2.6) rails-i18n rails_warden diff --git a/config/application.rb b/config/application.rb index 4771f89..4a70b04 100644 --- a/config/application.rb +++ b/config/application.rb @@ -7,12 +7,9 @@ require "action_mailer/railtie" require "sprockets/railtie" require "rails/test_unit/railtie" -if defined?(Bundler) - # If you precompile assets before deploying to production, use this line - Bundler.require(*Rails.groups(:assets => %w(development test))) - # If you want your assets lazily compiled in production, use this line - # Bundler.require(:default, :assets, Rails.env) -end +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) APP_CONFIG = ["defaults.yml", "config.yml"].inject({}) {|config, file| filepath = File.expand_path(file, File.dirname(__FILE__)) @@ -29,16 +26,6 @@ module LeapWeb # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. - # Custom directories with classes and modules you want to be autoloadable. - # config.autoload_paths += %W(#{config.root}/extras) - - # Only load the plugins named here, in the order given (default is alphabetical). - # :all can be used as a placeholder for all plugins not explicitly named. - # config.plugins = [ :exception_notification, :ssl_requirement, :all ] - - # Activate observers that should always be running. - # config.active_record.observers = :cacher, :garbage_collector, :forum_observer - # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' @@ -47,48 +34,18 @@ module LeapWeb # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de - # Configure the default encoding used in templates for Ruby 1.9. - config.encoding = "utf-8" - - # Configure sensitive parameters which will be filtered from the log file. - config.filter_parameters += [:password] - if APP_CONFIG[:logfile].present? config.logger = Logger.new(APP_CONFIG[:logfile]) end - # Enable escaping HTML in JSON. - config.active_support.escape_html_entities_in_json = true - - # Use SQL instead of Active Record's schema dumper when creating the database. - # This is necessary if your schema can't be completely dumped by the schema dumper, - # like if you have constraints or database-specific column types - # config.active_record.schema_format = :sql - - # Enforce whitelist mode for mass assignment. - # This will create an empty whitelist of attributes available for mass-assignment for all models - # in your app. As such, your models will need to explicitly whitelist or blacklist accessible - # parameters by using an attr_accessible or attr_protected declaration. - # config.active_record.whitelist_attributes = true - - ## - ## ASSETS - ## - - # Enable the asset pipeline - config.assets.enabled = true - config.assets.initialize_on_precompile = true # don't change this (see customization.rb) - - # Version of your assets, change this if you want to expire all your assets - config.assets.version = '1.0' - - # Set to false in order to see asset requests in the log - config.quiet_assets = true - ## ## CUSTOMIZATION ## see initializers/customization.rb ## + + # don't change this (see customization.rb) + config.assets.initialize_on_precompile = true + if APP_CONFIG["customization_directory"] custom_view_path = (Pathname.new(APP_CONFIG["customization_directory"]).relative_path_from(Rails.root) + 'views').to_s else diff --git a/config/boot.rb b/config/boot.rb index 4489e58..6b750f0 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,6 +1,3 @@ -require 'rubygems' - -# Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) -require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) +require 'bundler/setup' # Set up gems listed in the Gemfile. diff --git a/config/environment.rb b/config/environment.rb index fe16a54..00a613f 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,5 +1,5 @@ -# Load the rails application +# Load the rails application. require File.expand_path('../application', __FILE__) -# Initialize the rails application -LeapWeb::Application.initialize! +# Initialize the rails application. +Rails.application.initialize! -- cgit v1.2.3 From 9b9daf95357f4fa5fd1eb95b16e2cf043937bdc0 Mon Sep 17 00:00:00 2001 From: Azul Date: Thu, 24 Mar 2016 11:12:55 +0100 Subject: upgrade: default_wait_time -> default_max_wait_time --- test/support/browser_integration_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/support/browser_integration_test.rb b/test/support/browser_integration_test.rb index 5455fba..8201854 100644 --- a/test/support/browser_integration_test.rb +++ b/test/support/browser_integration_test.rb @@ -29,7 +29,7 @@ class BrowserIntegrationTest < ActionDispatch::IntegrationTest Capybara.app_host = 'http://lvh.me:3003' Capybara.server_port = 3003 Capybara.javascript_driver = :poltergeist - Capybara.default_wait_time = 5 + Capybara.default_max_wait_time = 5 # Make the Capybara DSL available include Capybara::DSL -- cgit v1.2.3 From afc1daac6745cd6b4543d2b542c6f03cfc32e1eb Mon Sep 17 00:00:00 2001 From: Azul Date: Thu, 24 Mar 2016 11:24:19 +0100 Subject: upgrade: client_side_validations initializer --- config/initializers/client_side_validations.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/config/initializers/client_side_validations.rb b/config/initializers/client_side_validations.rb index 252aded..f7a658a 100644 --- a/config/initializers/client_side_validations.rb +++ b/config/initializers/client_side_validations.rb @@ -1,9 +1,16 @@ # ClientSideValidations Initializer -# Uncomment to disable uniqueness validator, possible security issue -ClientSideValidations::Config.disabled_validators = [:uniqueness] +# Disabled validators. The uniqueness validator is disabled by default for security issues. Enable it on your own responsibility! +# ClientSideValidations::Config.disabled_validators = [:uniqueness] + +# Uncomment to validate number format with current I18n locale +# ClientSideValidations::Config.number_format_with_locale = true # Uncomment the following block if you want each input field to have the validation messages attached. +# +# Note: client_side_validation requires the error to be encapsulated within +# + ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| unless html_tag =~ /^