Commit 1935b494f6716d8410eaf8da59eb11c7f920b80c

Authored by Dmitriy Zaporozhets
2 parents f89a7471 dd68e37d

Merge branch 'refactor/profile_account' of /home/git/repositories/gitlab/gitlabhq

app/assets/stylesheets/common.scss
@@ -271,7 +271,6 @@ li.note { @@ -271,7 +271,6 @@ li.note {
271 } 271 }
272 272
273 .oauth_select_holder { 273 .oauth_select_holder {
274 - padding: 20px;  
275 img { 274 img {
276 padding: 5px; 275 padding: 5px;
277 margin-right: 10px; 276 margin-right: 10px;
app/controllers/profiles/accounts_controller.rb 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +class Profiles::AccountsController < ApplicationController
  2 + layout "profile"
  3 +
  4 + def show
  5 + @user = current_user
  6 + end
  7 +end
app/controllers/profiles/passwords_controller.rb
1 class Profiles::PasswordsController < ApplicationController 1 class Profiles::PasswordsController < ApplicationController
2 - layout 'navless' 2 + layout :determine_layout
3 3
4 - skip_before_filter :check_password_expiration 4 + skip_before_filter :check_password_expiration, only: [:new, :create]
5 5
6 before_filter :set_user 6 before_filter :set_user
7 before_filter :set_title 7 before_filter :set_title
  8 + before_filter :authorize_change_password!
8 9
9 def new 10 def new
10 end 11 end
@@ -26,6 +27,32 @@ class Profiles::PasswordsController &lt; ApplicationController @@ -26,6 +27,32 @@ class Profiles::PasswordsController &lt; ApplicationController
26 end 27 end
27 end 28 end
28 29
  30 + def edit
  31 + end
  32 +
  33 + def update
  34 + password_attributes = params[:user].select do |key, value|
  35 + %w(password password_confirmation).include?(key.to_s)
  36 + end
  37 +
  38 + unless @user.valid_password?(params[:user][:current_password])
  39 + redirect_to edit_profile_password_path, alert: 'You must provide a valid current password'
  40 + return
  41 + end
  42 +
  43 + if @user.update_attributes(password_attributes)
  44 + flash[:notice] = "Password was successfully updated. Please login with it"
  45 + redirect_to new_user_session_path
  46 + else
  47 + render 'edit'
  48 + end
  49 + end
  50 +
  51 + def reset
  52 + current_user.send_reset_password_instructions
  53 + redirect_to edit_profile_password_path, notice: 'We sent you an email with reset password instructions'
  54 + end
  55 +
29 private 56 private
30 57
31 def set_user 58 def set_user
@@ -35,4 +62,16 @@ class Profiles::PasswordsController &lt; ApplicationController @@ -35,4 +62,16 @@ class Profiles::PasswordsController &lt; ApplicationController
35 def set_title 62 def set_title
36 @title = "New password" 63 @title = "New password"
37 end 64 end
  65 +
  66 + def determine_layout
  67 + if [:new, :create].include?(action_name.to_sym)
  68 + 'navless'
  69 + else
  70 + 'profile'
  71 + end
  72 + end
  73 +
  74 + def authorize_change_password!
  75 + return render_404 if @user.ldap_user?
  76 + end
38 end 77 end
app/controllers/profiles_controller.rb
@@ -2,7 +2,6 @@ class ProfilesController &lt; ApplicationController @@ -2,7 +2,6 @@ class ProfilesController &lt; ApplicationController
2 include ActionView::Helpers::SanitizeHelper 2 include ActionView::Helpers::SanitizeHelper
3 3
4 before_filter :user 4 before_filter :user
5 - before_filter :authorize_change_password!, only: :update_password  
6 before_filter :authorize_change_username!, only: :update_username 5 before_filter :authorize_change_username!, only: :update_username
7 6
8 layout 'profile' 7 layout 'profile'
@@ -13,9 +12,6 @@ class ProfilesController &lt; ApplicationController @@ -13,9 +12,6 @@ class ProfilesController &lt; ApplicationController
13 def design 12 def design
14 end 13 end
15 14
16 - def account  
17 - end  
18 -  
19 def update 15 def update
20 if @user.update_attributes(params[:user]) 16 if @user.update_attributes(params[:user])
21 flash[:notice] = "Profile was successfully updated" 17 flash[:notice] = "Profile was successfully updated"
@@ -29,33 +25,12 @@ class ProfilesController &lt; ApplicationController @@ -29,33 +25,12 @@ class ProfilesController &lt; ApplicationController
29 end 25 end
30 end 26 end
31 27
32 - def token  
33 - end  
34 -  
35 - def update_password  
36 - password_attributes = params[:user].select do |key, value|  
37 - %w(password password_confirmation).include?(key.to_s)  
38 - end  
39 -  
40 - unless @user.valid_password?(params[:user][:current_password])  
41 - redirect_to account_profile_path, alert: 'You must provide a valid current password'  
42 - return  
43 - end  
44 -  
45 - if @user.update_attributes(password_attributes)  
46 - flash[:notice] = "Password was successfully updated. Please login with it"  
47 - redirect_to new_user_session_path  
48 - else  
49 - render 'account'  
50 - end  
51 - end  
52 -  
53 def reset_private_token 28 def reset_private_token
54 if current_user.reset_authentication_token! 29 if current_user.reset_authentication_token!
55 flash[:notice] = "Token was successfully updated" 30 flash[:notice] = "Token was successfully updated"
56 end 31 end
57 32
58 - redirect_to account_profile_path 33 + redirect_to profile_account_path
59 end 34 end
60 35
61 def history 36 def history
@@ -76,10 +51,6 @@ class ProfilesController &lt; ApplicationController @@ -76,10 +51,6 @@ class ProfilesController &lt; ApplicationController
76 @user = current_user 51 @user = current_user
77 end 52 end
78 53
79 - def authorize_change_password!  
80 - return render_404 if @user.ldap_user?  
81 - end  
82 -  
83 def authorize_change_username! 54 def authorize_change_username!
84 return render_404 unless @user.can_change_username? 55 return render_404 unless @user.can_change_username?
85 end 56 end
app/views/layouts/nav/_profile.html.haml
@@ -2,8 +2,11 @@ @@ -2,8 +2,11 @@
2 = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do 2 = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
3 = link_to profile_path, title: "Profile" do 3 = link_to profile_path, title: "Profile" do
4 %i.icon-home 4 %i.icon-home
5 - = nav_link(path: 'profiles#account') do  
6 - = link_to "Account", account_profile_path 5 + = nav_link(controller: :accounts) do
  6 + = link_to "Account", profile_account_path
  7 + - unless current_user.ldap_user?
  8 + = nav_link(controller: :passwords) do
  9 + = link_to "Password", edit_profile_password_path
7 = nav_link(controller: :notifications) do 10 = nav_link(controller: :notifications) do
8 = link_to "Notifications", profile_notifications_path 11 = link_to "Notifications", profile_notifications_path
9 = nav_link(controller: :keys) do 12 = nav_link(controller: :keys) do
app/views/profiles/account.html.haml
@@ -1,141 +0,0 @@ @@ -1,141 +0,0 @@
1 -%h3.page-title  
2 - Account settings  
3 -%p.light  
4 - You can change your password, username and private token here.  
5 - - if current_user.ldap_user?  
6 - Some options are unavailable for LDAP accounts  
7 -%hr  
8 -  
9 -  
10 -.row  
11 - .span2  
12 - %ul.nav.nav-pills.nav-stacked.nav-stacked-menu  
13 - %li.active  
14 - = link_to '#tab-token', 'data-toggle' => 'tab' do  
15 - Private Token  
16 - %li  
17 - = link_to '#tab-password', 'data-toggle' => 'tab' do  
18 - Password  
19 -  
20 - - if show_profile_social_tab?  
21 - %li  
22 - = link_to '#tab-social', 'data-toggle' => 'tab' do  
23 - Social Accounts  
24 -  
25 - - if show_profile_username_tab?  
26 - %li  
27 - = link_to '#tab-username', 'data-toggle' => 'tab' do  
28 - Change Username  
29 -  
30 - - if show_profile_remove_tab?  
31 - %li  
32 - = link_to '#tab-remove', 'data-toggle' => 'tab' do  
33 - Remove Account  
34 - .span10  
35 - .tab-content  
36 - .tab-pane.active#tab-token  
37 - %fieldset.update-token  
38 - %legend  
39 - Private token  
40 - %span.cred.pull-right  
41 - keep it secret!  
42 - %div  
43 - = form_for @user, url: reset_private_token_profile_path, method: :put do |f|  
44 - .data  
45 - %p.slead  
46 - Your private token is used to access application resources without authentication.  
47 - %br  
48 - It can be used for atom feeds or the API.  
49 - %p.cgray  
50 - - if current_user.private_token  
51 - = text_field_tag "token", current_user.private_token, class: "input-xxlarge large_text input-xpadding"  
52 - = f.submit 'Reset', confirm: "Are you sure?", class: "btn btn-primary btn-build-token"  
53 - - else  
54 - %span You don`t have one yet. Click generate to fix it.  
55 - = f.submit 'Generate', class: "btn success btn-build-token"  
56 -  
57 - .tab-pane#tab-password  
58 - %fieldset.update-password  
59 - %legend Password  
60 - - if current_user.ldap_user?  
61 - %h3.nothing_here_message Not available for LDAP user  
62 - - else  
63 - = form_for @user, url: update_password_profile_path, method: :put do |f|  
64 - %div  
65 - %p.slead  
66 - You must provide current password in order to change it.  
67 - %br  
68 - After a successful password update you will be redirected to login page where you should login with your new password  
69 - -if @user.errors.any?  
70 - .alert.alert-error  
71 - %ul  
72 - - @user.errors.full_messages.each do |msg|  
73 - %li= msg  
74 - .control-group  
75 - = f.label :current_password, class: 'cgreen'  
76 - .controls= f.password_field :current_password, required: true  
77 - .control-group  
78 - = f.label :password, 'New password'  
79 - .controls= f.password_field :password, required: true  
80 - .control-group  
81 - = f.label :password_confirmation  
82 - .controls  
83 - = f.password_field :password_confirmation, required: true  
84 - .control-group  
85 - .controls  
86 - = f.submit 'Save password', class: "btn btn-save"  
87 -  
88 - - if show_profile_social_tab?  
89 - .tab-pane#tab-social  
90 - %fieldset  
91 - %legend Social Accounts  
92 - .oauth_select_holder  
93 - %p.hint Tip: Click on icon to activate signin with one of the following services  
94 - - enabled_social_providers.each do |provider|  
95 - %span{class: oauth_active_class(provider) }  
96 - = link_to authbutton(provider, 32), omniauth_authorize_path(User, provider)  
97 -  
98 - - if show_profile_username_tab?  
99 - .tab-pane#tab-username  
100 - %fieldset.update-username  
101 - %legend  
102 - Username  
103 - %small.cred.pull-right  
104 - Changing your username can have unintended side effects!  
105 - = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f|  
106 - %div  
107 - .control-group  
108 - = f.label :username  
109 - .controls  
110 - = f.text_field :username, required: true  
111 - &nbsp;  
112 - %span.loading-gif.hide= image_tag "ajax_loader.gif"  
113 - %span.update-success.cgreen.hide  
114 - %i.icon-ok  
115 - Saved  
116 - %span.update-failed.cred.hide  
117 - %i.icon-remove  
118 - Failed  
119 - %ul.cred  
120 - %li This will change the web URL for personal projects.  
121 - %li This will change the git path to repositories for personal projects.  
122 - .controls  
123 - = f.submit 'Save username', class: "btn btn-save"  
124 -  
125 - - if show_profile_remove_tab?  
126 - .tab-pane#tab-remove  
127 - %fieldset.remove-account  
128 - %legend  
129 - Remove account  
130 - %div  
131 - %p Deleting an account has the following effects:  
132 - %ul  
133 - %li All user content like authored issues, snippets, comments will be removed  
134 - - rp = current_user.personal_projects.count  
135 - - unless rp.zero?  
136 - %li #{pluralize rp, 'personal project'} will be removed and cannot be restored  
137 - - if current_user.solo_owned_groups.present?  
138 - %li  
139 - Next groups will be abandoned. You should transfer or remove them:  
140 - %strong #{current_user.solo_owned_groups.map(&:name).join(', ')}  
141 - = link_to 'Delete account', user_registration_path, confirm: "REMOVE #{current_user.name}? Are you sure?", method: :delete, class: "btn btn-remove"  
app/views/profiles/accounts/show.html.haml 0 → 100644
@@ -0,0 +1,73 @@ @@ -0,0 +1,73 @@
  1 +%h3.page-title
  2 + Account settings
  3 +%p.light
  4 + You can change your username and private token here.
  5 + - if current_user.ldap_user?
  6 + Some options are unavailable for LDAP accounts
  7 +%hr
  8 +
  9 +
  10 +%div
  11 + %fieldset.update-token
  12 + %legend
  13 + Private token
  14 + %div
  15 + = form_for @user, url: reset_private_token_profile_path, method: :put do |f|
  16 + .data
  17 + %p
  18 + Your private token is used to access application resources without authentication.
  19 + %br
  20 + It can be used for atom feeds or the API.
  21 + %span.cred
  22 + Keep it secret!
  23 +
  24 + %p.cgray
  25 + - if current_user.private_token
  26 + = text_field_tag "token", current_user.private_token, class: "input-xlarge input-xpadding pull-left"
  27 + = f.submit 'Reset', confirm: "Are you sure?", class: "btn btn-primary btn-build-token prepend-left-10"
  28 + - else
  29 + %span You don`t have one yet. Click generate to fix it.
  30 + = f.submit 'Generate', class: "btn success btn-build-token"
  31 +
  32 +
  33 + - if show_profile_social_tab?
  34 + %fieldset
  35 + %legend Social Accounts
  36 + .oauth_select_holder
  37 + %p Click on icon to activate signin with one of the following services
  38 + - enabled_social_providers.each do |provider|
  39 + %span{class: oauth_active_class(provider) }
  40 + = link_to authbutton(provider, 32), omniauth_authorize_path(User, provider)
  41 +
  42 + - if show_profile_username_tab?
  43 + %fieldset.update-username
  44 + %legend
  45 + Username
  46 + = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f|
  47 + %p
  48 + Changing your username will change path to all personl projects!
  49 + %div
  50 + = f.text_field :username, required: true, class: 'input-xlarge input-xpadding'
  51 + &nbsp;
  52 + %span.loading-gif.hide= image_tag "ajax_loader.gif"
  53 + %p.light
  54 + = user_url(@user)
  55 + %div
  56 + = f.submit 'Save username', class: "btn btn-save"
  57 +
  58 + - if show_profile_remove_tab?
  59 + %fieldset.remove-account
  60 + %legend
  61 + Remove account
  62 + %div
  63 + %p Deleting an account has the following effects:
  64 + %ul
  65 + %li All user content like authored issues, snippets, comments will be removed
  66 + - rp = current_user.personal_projects.count
  67 + - unless rp.zero?
  68 + %li #{pluralize rp, 'personal project'} will be removed and cannot be restored
  69 + - if current_user.solo_owned_groups.present?
  70 + %li
  71 + Next groups will be abandoned. You should transfer or remove them:
  72 + %strong #{current_user.solo_owned_groups.map(&:name).join(', ')}
  73 + = link_to 'Delete account', user_registration_path, confirm: "REMOVE #{current_user.name}? Are you sure?", method: :delete, class: "btn btn-remove"
app/views/profiles/passwords/edit.html.haml 0 → 100644
@@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
  1 +%h3.page-title Password
  2 +%p.light
  3 + Change your password or recover your current one.
  4 +%hr
  5 +.update-password
  6 + = form_for @user, url: profile_password_path, method: :put do |f|
  7 + %div
  8 + %p.slead
  9 + You must provide current password in order to change it.
  10 + %br
  11 + After a successful password update you will be redirected to login page where you should login with your new password
  12 + -if @user.errors.any?
  13 + .alert.alert-error
  14 + %ul
  15 + - @user.errors.full_messages.each do |msg|
  16 + %li= msg
  17 + .control-group
  18 + = f.label :current_password
  19 + .controls
  20 + = f.password_field :current_password, required: true
  21 + %div
  22 + = link_to "Forgot your password?", reset_profile_password_path, method: :put
  23 +
  24 + .control-group
  25 + = f.label :password, 'New password'
  26 + .controls= f.password_field :password, required: true
  27 + .control-group
  28 + = f.label :password_confirmation
  29 + .controls
  30 + = f.password_field :password_confirmation, required: true
  31 + .form-actions
  32 + = f.submit 'Save password', class: "btn btn-save"
app/views/profiles/update_username.js.haml
1 - if @user.valid? 1 - if @user.valid?
2 :plain 2 :plain
3 - $('.update-username .update-success').show(); 3 + new Flash("Username sucessfully changed", "notice")
4 - else 4 - else
5 :plain 5 :plain
6 - $('.update-username .update-failed').show(); 6 + new Flash("Username change failed - #{@user.errors.full_messages.first}", "alert")
config/routes.rb
@@ -99,19 +99,21 @@ Gitlab::Application.routes.draw do @@ -99,19 +99,21 @@ Gitlab::Application.routes.draw do
99 # 99 #
100 resource :profile, only: [:show, :update] do 100 resource :profile, only: [:show, :update] do
101 member do 101 member do
102 - get :account  
103 get :history 102 get :history
104 - get :token  
105 get :design 103 get :design
106 104
107 - put :update_password  
108 put :reset_private_token 105 put :reset_private_token
109 put :update_username 106 put :update_username
110 end 107 end
111 108
112 scope module: :profiles do 109 scope module: :profiles do
  110 + resource :account, only: [:show, :update]
113 resource :notifications, only: [:show, :update] 111 resource :notifications, only: [:show, :update]
114 - resource :password, only: [:new, :create] 112 + resource :password, only: [:new, :create, :edit, :update] do
  113 + member do
  114 + put :reset
  115 + end
  116 + end
115 resources :keys 117 resources :keys
116 resources :groups, only: [:index] do 118 resources :groups, only: [:index] do
117 member do 119 member do
features/profile/profile.feature
@@ -12,13 +12,13 @@ Feature: Profile @@ -12,13 +12,13 @@ Feature: Profile
12 And I should see new contact info 12 And I should see new contact info
13 13
14 Scenario: I change my password without old one 14 Scenario: I change my password without old one
15 - Given I visit profile account page 15 + Given I visit profile password page
16 When I try change my password w/o old one 16 When I try change my password w/o old one
17 Then I should see a missing password error message 17 Then I should see a missing password error message
18 - And I should be redirected to account page 18 + And I should be redirected to password page
19 19
20 Scenario: I change my password 20 Scenario: I change my password
21 - Given I visit profile account page 21 + Given I visit profile password page
22 Then I change my password 22 Then I change my password
23 And I should be redirected to sign in page 23 And I should be redirected to sign in page
24 24
@@ -30,13 +30,13 @@ Feature: Profile @@ -30,13 +30,13 @@ Feature: Profile
30 Scenario: My password is expired 30 Scenario: My password is expired
31 Given my password is expired 31 Given my password is expired
32 And I am not an ldap user 32 And I am not an ldap user
33 - And I visit profile account page 33 + Given I visit profile password page
34 Then I redirected to expired password page 34 Then I redirected to expired password page
35 And I submit new password 35 And I submit new password
36 And I redirected to sign in page 36 And I redirected to sign in page
37 37
38 Scenario: I unsuccessfully change my password 38 Scenario: I unsuccessfully change my password
39 - Given I visit profile account page 39 + Given I visit profile password page
40 When I unsuccessfully change my password 40 When I unsuccessfully change my password
41 Then I should see a password error message 41 Then I should see a password error message
42 42
features/steps/profile/profile.rb
@@ -133,8 +133,12 @@ class Profile &lt; Spinach::FeatureSteps @@ -133,8 +133,12 @@ class Profile &lt; Spinach::FeatureSteps
133 current_path.should == new_user_session_path 133 current_path.should == new_user_session_path
134 end 134 end
135 135
  136 + step 'I should be redirected to password page' do
  137 + current_path.should == edit_profile_password_path
  138 + end
  139 +
136 step 'I should be redirected to account page' do 140 step 'I should be redirected to account page' do
137 - current_path.should == account_profile_path 141 + current_path.should == profile_account_path
138 end 142 end
139 143
140 step 'I click on my profile picture' do 144 step 'I click on my profile picture' do
features/steps/shared/paths.rb
@@ -65,8 +65,12 @@ module SharedPaths @@ -65,8 +65,12 @@ module SharedPaths
65 visit profile_path 65 visit profile_path
66 end 66 end
67 67
  68 + step 'I visit profile password page' do
  69 + visit edit_profile_password_path
  70 + end
  71 +
68 step 'I visit profile account page' do 72 step 'I visit profile account page' do
69 - visit account_profile_path 73 + visit profile_account_path
70 end 74 end
71 75
72 step 'I visit profile SSH keys page' do 76 step 'I visit profile SSH keys page' do
spec/features/profile_spec.rb
@@ -12,7 +12,7 @@ describe &quot;Profile account page&quot; do @@ -12,7 +12,7 @@ describe &quot;Profile account page&quot; do
12 describe "when signup is enabled" do 12 describe "when signup is enabled" do
13 before do 13 before do
14 Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) 14 Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
15 - visit account_profile_path 15 + visit profile_account_path
16 end 16 end
17 17
18 it { page.should have_content("Remove account") } 18 it { page.should have_content("Remove account") }
@@ -26,12 +26,12 @@ describe &quot;Profile account page&quot; do @@ -26,12 +26,12 @@ describe &quot;Profile account page&quot; do
26 describe "when signup is disabled" do 26 describe "when signup is disabled" do
27 before do 27 before do
28 Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) 28 Gitlab.config.gitlab.stub(:signup_enabled).and_return(false)
29 - visit account_profile_path 29 + visit profile_account_path
30 end 30 end
31 31
32 it "should not have option to remove account" do 32 it "should not have option to remove account" do
33 page.should_not have_content("Remove account") 33 page.should_not have_content("Remove account")
34 - current_path.should == account_profile_path 34 + current_path.should == profile_account_path
35 end 35 end
36 end 36 end
37 end 37 end
spec/features/security/profile_access_spec.rb
@@ -29,7 +29,7 @@ describe &quot;Users Security&quot; do @@ -29,7 +29,7 @@ describe &quot;Users Security&quot; do
29 end 29 end
30 30
31 describe "GET /profile/account" do 31 describe "GET /profile/account" do
32 - subject { account_profile_path } 32 + subject { profile_account_path }
33 33
34 it { should be_allowed_for @u1 } 34 it { should be_allowed_for @u1 }
35 it { should be_allowed_for :admin } 35 it { should be_allowed_for :admin }
spec/routing/routing_spec.rb
@@ -128,7 +128,7 @@ end @@ -128,7 +128,7 @@ end
128 # profile_update PUT /profile/update(.:format) profile#update 128 # profile_update PUT /profile/update(.:format) profile#update
129 describe ProfilesController, "routing" do 129 describe ProfilesController, "routing" do
130 it "to #account" do 130 it "to #account" do
131 - get("/profile/account").should route_to('profiles#account') 131 + get("/profile/account").should route_to('profiles/accounts#show')
132 end 132 end
133 133
134 it "to #history" do 134 it "to #history" do