diff options
| -rw-r--r-- | Gemfile.lock | 10 | ||||
| -rw-r--r-- | config/defaults.yml | 6 | ||||
| -rw-r--r-- | core/leap_web_core.gemspec | 2 | ||||
| -rw-r--r-- | core/lib/extensions/couchrest.rb | 8 | ||||
| -rw-r--r-- | test/integration/os_detection_test.rb (renamed from test/integration/home_test.rb) | 2 | ||||
| -rw-r--r-- | users/app/views/users/_change_password.html.haml | 21 | ||||
| -rw-r--r-- | users/app/views/users/_change_pgp_key.html.haml | 13 | ||||
| -rw-r--r-- | users/app/views/users/_change_service_level.html.haml | 18 | ||||
| -rw-r--r-- | users/app/views/users/_destroy_account.html.haml | 27 | ||||
| -rw-r--r-- | users/app/views/users/_edit.html.haml | 93 | ||||
| -rw-r--r-- | users/test/integration/browser/account_test.rb | 66 | 
11 files changed, 150 insertions, 116 deletions
| diff --git a/Gemfile.lock b/Gemfile.lock index d1fd014..918fdba 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -25,7 +25,7 @@ PATH      leap_web_core (0.2.8)        couchrest (~> 1.1.3)        couchrest_model (~> 2.0.0) -      couchrest_session_store (~> 0.2.2) +      couchrest_session_store (~> 0.2.4)        json        rails (~> 3.2.11) @@ -105,12 +105,12 @@ GEM        mime-types (~> 1.15)        multi_json (~> 1.0)        rest-client (~> 1.6.1) -    couchrest_model (2.0.0) +    couchrest_model (2.0.1)        activemodel (>= 3.0)        couchrest (~> 1.1.3)        mime-types (>= 1.15)        tzinfo (>= 0.3.22) -    couchrest_session_store (0.2.2) +    couchrest_session_store (0.2.4)        actionpack        couchrest        couchrest_model @@ -145,7 +145,7 @@ GEM        haml (~> 3.1)        railties (>= 3.1, < 4.1)      hike (1.2.3) -    i18n (0.6.5) +    i18n (0.6.9)      journey (1.0.4)      jquery-rails (3.0.4)        railties (>= 3.0, < 5.0) @@ -162,7 +162,7 @@ GEM        mime-types (~> 1.16)        treetop (~> 1.4.8)      metaclass (0.0.1) -    mime-types (1.25) +    mime-types (1.25.1)      mini_portile (0.5.1)      mocha (0.13.3)        metaclass (~> 0.0.1) diff --git a/config/defaults.yml b/config/defaults.yml index 4530d47..260915e 100644 --- a/config/defaults.yml +++ b/config/defaults.yml @@ -40,6 +40,10 @@ common: &common    handle_blacklist: [certmaster, ssladmin, arin-admin, administrator, www-data, maildrop]    # handles that will be allowed despite being in /etc/passwd or rfc2142    handle_whitelist: [] +  # actions enabled in the account settings +  # see /users/app/views/users/_edit.html.haml for a list. +  user_actions: ['destroy_account'] +  admin_actions: ['change_pgp_key', 'change_service_level', 'destroy_account']  service_levels: &service_levels    service_levels: @@ -72,6 +76,7 @@ development:    domain: example.org    secret_token: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'    payment: [] +  reraise_errors: true  test:    <<: *downloads @@ -83,6 +88,7 @@ test:    domain: test.me    secret_token: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'    payment: [billing] +  reraise_errors: true  production:    <<: *downloads diff --git a/core/leap_web_core.gemspec b/core/leap_web_core.gemspec index 4109a03..7ca4d90 100644 --- a/core/leap_web_core.gemspec +++ b/core/leap_web_core.gemspec @@ -19,7 +19,7 @@ Gem::Specification.new do |s|    s.add_dependency "couchrest", "~> 1.1.3"    s.add_dependency "couchrest_model", "~> 2.0.0" -  s.add_dependency "couchrest_session_store", "~> 0.2.2" +  s.add_dependency "couchrest_session_store", "~> 0.2.4"    s.add_dependency "json"  end diff --git a/core/lib/extensions/couchrest.rb b/core/lib/extensions/couchrest.rb index 84cfbb3..9f27c3a 100644 --- a/core/lib/extensions/couchrest.rb +++ b/core/lib/extensions/couchrest.rb @@ -23,10 +23,6 @@ module CouchRest        end      end -    module Errors -      class ConnectionFailed < CouchRestModelError; end -    end -      module Connection        module ClassMethods @@ -36,7 +32,9 @@ module CouchRest          rescue RestClient::Unauthorized,            Errno::EHOSTUNREACH,            Errno::ECONNREFUSED => e -          raise CouchRest::Model::Errors::ConnectionFailed.new(e.to_s) +          message = "Could not connect to couch database #{db} due to #{e.to_s}" +          Rails.logger.warn message +          raise e.class.new(message) if APP_CONFIG[:reraise_errors]          end        end diff --git a/test/integration/home_test.rb b/test/integration/os_detection_test.rb index 126a420..cb254aa 100644 --- a/test/integration/home_test.rb +++ b/test/integration/os_detection_test.rb @@ -1,6 +1,6 @@  require 'test_helper' -class AccountTest < BrowserIntegrationTest +class OsDetectionTest < BrowserIntegrationTest    setup do      Capybara.current_driver = Capybara.javascript_driver diff --git a/users/app/views/users/_change_password.html.haml b/users/app/views/users/_change_password.html.haml new file mode 100644 index 0000000..425e3ee --- /dev/null +++ b/users/app/views/users/_change_password.html.haml @@ -0,0 +1,21 @@ +-# +-# CHANGE PASSWORD +-# +-# * everything about this form is handled with javascript. So take care when changing any ids. +-# * the login is required when changing the password because it is used as part of the salt when calculating the password verifier. +-#   however, we don't want the user to change their login without generating a new key, so we hide the ui for this +-#   (although it works perfectly fine to change username if the field was visible). +-# + +- form_options = {:url => '/not-used', :html => {:class => user_form_class('form-horizontal'), :id =>  'update_login_and_password', :data => {token: session[:token]}}, :validate => true} += simple_form_for @user, form_options do |f| +  %legend= t(:change_password) +  = hidden_field_tag 'user_param', @user.to_param +  .hidden +    = f.input :login, :label => t(:username), :required => false, :input_html => {:id => :srp_username} +  = f.input :password, :required => false, :validate => true, :input_html => { :id => :srp_password } +  = f.input :password_confirmation, :required => false, :input_html => { :id => :srp_password_confirmation } +  .control-group +    .controls +      = f.submit t(:save), :class => 'btn btn-primary' + diff --git a/users/app/views/users/_change_pgp_key.html.haml b/users/app/views/users/_change_pgp_key.html.haml new file mode 100644 index 0000000..e465125 --- /dev/null +++ b/users/app/views/users/_change_pgp_key.html.haml @@ -0,0 +1,13 @@ +-# +-# CHANGE PGP KEY +-# +-# this will be replaced by a identities controller/view at some point +-# + +- form_options = {:html => {:class => user_form_class('form-horizontal'), :id => 'update_pgp_key', :data => {token: session[:token]}}, :validate => true} += simple_form_for [:api, @user], form_options do |f| +  %legend= t(:advanced_options) +  = f.input :public_key, :as => :text, :hint => t(:use_ascii_key), :input_html => {:class => "full-width", :rows => 4} +  .control-group +    .controls +      = f.submit t(:save), :class => 'btn', :data => {"loading-text" => "Saving..."} diff --git a/users/app/views/users/_change_service_level.html.haml b/users/app/views/users/_change_service_level.html.haml new file mode 100644 index 0000000..61e67d9 --- /dev/null +++ b/users/app/views/users/_change_service_level.html.haml @@ -0,0 +1,18 @@ +-# TODO: probably won't want here, but here for now. Also, we will need way to ensure payment if they pick a non-free plan. +-# +-# SERVICE LEVEL +-# +- if APP_CONFIG[:service_levels] +  - form_options = {:html => {:class => user_form_class('form-horizontal'), :id => 'update_service_level', :data => {token: session[:token]}}, :validate => true} +  = simple_form_for @user, form_options do |f| +    %legend= t(:service_level) +    - if @user != current_user +      = t(:desired_service_level) +    = f.select :desired_service_level_code, ServiceLevel.authenticated_select_options, :selected => @user.desired_service_level.id +    - if @user != current_user +      %p +      = t(:effective_service_level) +      = f.select :effective_service_level_code, ServiceLevel.authenticated_select_options, :selected => @user.effective_service_level.id +    .control-group +      .controls +        = f.submit t(:save), :class => 'btn', :data => {"loading-text" => "Saving..."} diff --git a/users/app/views/users/_destroy_account.html.haml b/users/app/views/users/_destroy_account.html.haml new file mode 100644 index 0000000..445f3c4 --- /dev/null +++ b/users/app/views/users/_destroy_account.html.haml @@ -0,0 +1,27 @@ +-# +-# DESTROY ACCOUNT +-# + +%legend +  - if @user == current_user +    = t(:destroy_my_account) +  - else +    = t(:admin_destroy_account, :username => @user.login) +%p= t(:destroy_account_info) += link_to user_path(@user), :method => :delete, :confirm => t(:are_you_sure), :class => "btn btn-danger" do +  %i.icon-remove.icon-white +  = t(:destroy_my_account) +- if @user != current_user and @user.enabled? +  %legend +    = t(:deactivate_account, :username => @user.login) +  %p= t(:deactivate_description) +  = link_to deactivate_user_path(@user), :method => :post, :class => "btn btn-warning"  do +    %i.icon-pause.icon-white +    = t(:deactivate) +- elsif @user != current_user and !@user.enabled? +  %legend +    = t(:enable_account, :username => @user.login) +  %p= t(:enable_description) +  = link_to enable_user_path(@user), :method => :post, :class => "btn btn-warning"  do +    %i.icon-ok.icon-white +    = t(:enable) diff --git a/users/app/views/users/_edit.html.haml b/users/app/views/users/_edit.html.haml index 0b36d6e..1d2b68a 100644 --- a/users/app/views/users/_edit.html.haml +++ b/users/app/views/users/_edit.html.haml @@ -1,85 +1,14 @@  -#  -# edit user form, used by both show and edit actions.  -# - --# --# CHANGE PASSWORD --# --# * everything about this form is handled with javascript. So take care when changing any ids. --# * the login is required when changing the password because it is used as part of the salt when calculating the password verifier. --#   however, we don't want the user to change their login without generating a new key, so we hide the ui for this --#   (although it works perfectly fine to change username if the field was visible). --# - -- form_options = {:url => '/not-used', :html => {:class => user_form_class('form-horizontal'), :id =>  'update_login_and_password', :data => {token: session[:token]}}, :validate => true} -= simple_form_for @user, form_options do |f| -  %legend= t(:change_password) -  = hidden_field_tag 'user_param', @user.to_param -  .hidden -    = f.input :login, :label => t(:username), :required => false, :input_html => {:id => :srp_username} -  = f.input :password, :required => false, :validate => true, :input_html => { :id => :srp_password } -  = f.input :password_confirmation, :required => false, :input_html => { :id => :srp_password_confirmation } -  .control-group -    .controls -      = f.submit t(:save), :class => 'btn btn-primary' - --# --# CHANGE PGP KEY --# --# this will be replaced by a identities controller/view at some point --# - -- form_options = {:html => {:class => user_form_class('form-horizontal'), :id => 'update_pgp_key', :data => {token: session[:token]}}, :validate => true} -= simple_form_for [:api, @user], form_options do |f| -  %legend= t(:advanced_options) -  = f.input :public_key, :as => :text, :hint => t(:use_ascii_key), :input_html => {:class => "full-width", :rows => 4} -  .control-group -    .controls -      = f.submit t(:save), :class => 'btn', :data => {"loading-text" => "Saving..."} - - --# TODO: probably won't want here, but here for now. Also, we will need way to ensure payment if they pick a non-free plan. --# --# SERVICE LEVEL --# -- if APP_CONFIG[:service_levels] -  - form_options = {:html => {:class => user_form_class('form-horizontal'), :id => 'update_service_level', :data => {token: session[:token]}}, :validate => true} -  = simple_form_for @user, form_options do |f| -    %legend= t(:service_level) -    - if @user != current_user -      = t(:desired_service_level) -    = f.select :desired_service_level_code, ServiceLevel.authenticated_select_options, :selected => @user.desired_service_level.id -    - if @user != current_user -      %p -      = t(:effective_service_level) -      = f.select :effective_service_level_code, ServiceLevel.authenticated_select_options, :selected => @user.effective_service_level.id -    .control-group -      .controls -        = f.submit t(:save), :class => 'btn', :data => {"loading-text" => "Saving..."} --# --# DESTROY ACCOUNT --# - -%legend -  - if @user == current_user -    = t(:destroy_my_account) -  - else -    = t(:admin_destroy_account, :username => @user.login) -%p= t(:destroy_account_info) -= link_to user_path(@user), :method => :delete, :confirm => t(:are_you_sure), :class => "btn btn-danger" do -  %i.icon-remove.icon-white -  = t(:destroy_my_account) -- if @user != current_user and @user.enabled? -  %legend -    = t(:deactivate_account, :username => @user.login) -  %p= t(:deactivate_description) -  = link_to deactivate_user_path(@user), :method => :post, :class => "btn btn-warning"  do -    %i.icon-pause.icon-white -    = t(:deactivate) -- elsif @user != current_user and !@user.enabled? -  %legend -    = t(:enable_account, :username => @user.login) -  %p= t(:enable_description) -  = link_to enable_user_path(@user), :method => :post, :class => "btn btn-warning"  do -    %i.icon-ok.icon-white -    = t(:enable) +-# We render a bunch of forms here. Which we use depends upon config settings +-# user_actions and admin_actions. They both include an array of actions  +-# allowed to users and admins. +-# Possible forms are: +-#  'change_password' +-#  'change_pgp_key' +-#  'change_service_level' +-#  'destroy_account' +- actions = APP_CONFIG[admin? ? :admin_actions : :user_actions] || [] +- actions.each do |action| +  = render action diff --git a/users/test/integration/browser/account_test.rb b/users/test/integration/browser/account_test.rb index 3d281ae..4cefe35 100644 --- a/users/test/integration/browser/account_test.rb +++ b/users/test/integration/browser/account_test.rb @@ -51,35 +51,57 @@ class AccountTest < BrowserIntegrationTest      assert page.has_content?('has already been taken')    end -  test "change password" do +  test "default user actions" do      username, password = submit_signup      click_on "Account Settings" -    within('#update_login_and_password') do -      fill_in 'Password', with: "other password" -      fill_in 'Password confirmation', with: "other password" -      click_on 'Save' +    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 +    username, password = submit_signup +    with_config admins: [username] 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 password" do +    with_config user_actions: ['change_password'] do +      username, password = submit_signup +      click_on "Account Settings" +      within('#update_login_and_password') do +        fill_in 'Password', with: "other password" +        fill_in 'Password confirmation', with: "other password" +        click_on 'Save' +      end +      click_on 'Logout' +      attempt_login(username, "other password") +      assert page.has_content?("Welcome #{username}") +      User.find_by_login(username).account.destroy      end -    click_on 'Logout' -    attempt_login(username, "other password") -    assert page.has_content?("Welcome #{username}") -    User.find_by_login(username).account.destroy    end    test "change pgp key" do -    pgp_key = FactoryGirl.build :pgp_key -    username, password = submit_signup -    click_on "Account Settings" -    within('#update_pgp_key') do -      fill_in 'Public key', with: pgp_key -      click_on 'Save' +    with_config user_actions: ['change_pgp_key'] do +      pgp_key = FactoryGirl.build :pgp_key +      username, password = submit_signup +      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 = User.find_by_login(username) +      assert_equal pgp_key, user.public_key +      user.account.destroy      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 = User.find_by_login(username) -    assert_equal pgp_key, user.public_key -    user.account.destroy    end | 
