@@ -0,0 +1,11 | |||
|
1 | <h2><%=l(:label_confirmation)%></h2> | |
|
2 | <div class="warning"> | |
|
3 | <p><%= simple_format l(:text_account_destroy_confirmation)%></p> | |
|
4 | <p> | |
|
5 | <% form_tag({}) do %> | |
|
6 | <label><%= check_box_tag 'confirm', 1 %> <%= l(:general_text_Yes) %></label> | |
|
7 | <%= submit_tag l(:button_delete_my_account) %> | | |
|
8 | <%= link_to l(:button_cancel), :action => 'account' %> | |
|
9 | <% end %> | |
|
10 | </p> | |
|
11 | </div> |
@@ -131,14 +131,6 class AccountController < ApplicationController | |||
|
131 | 131 | |
|
132 | 132 | private |
|
133 | 133 | |
|
134 | def logout_user | |
|
135 | if User.current.logged? | |
|
136 | cookies.delete :autologin | |
|
137 | Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) | |
|
138 | self.logged_user = nil | |
|
139 | end | |
|
140 | end | |
|
141 | ||
|
142 | 134 | def authenticate_user |
|
143 | 135 | if Setting.openid? && using_open_id? |
|
144 | 136 | open_id_authenticate(params[:openid_url]) |
@@ -126,6 +126,15 class ApplicationController < ActionController::Base | |||
|
126 | 126 | end |
|
127 | 127 | end |
|
128 | 128 | |
|
129 | # Logs out current user | |
|
130 | def logout_user | |
|
131 | if User.current.logged? | |
|
132 | cookies.delete :autologin | |
|
133 | Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) | |
|
134 | self.logged_user = nil | |
|
135 | end | |
|
136 | end | |
|
137 | ||
|
129 | 138 | # check if login is globally required to access the application |
|
130 | 139 | def check_if_login_required |
|
131 | 140 | # no check needed if user is already logged in |
@@ -65,6 +65,24 class MyController < ApplicationController | |||
|
65 | 65 | end |
|
66 | 66 | end |
|
67 | 67 | |
|
68 | # Destroys user's account | |
|
69 | def destroy | |
|
70 | @user = User.current | |
|
71 | unless @user.own_account_deletable? | |
|
72 | redirect_to :action => 'account' | |
|
73 | return | |
|
74 | end | |
|
75 | ||
|
76 | if request.post? && params[:confirm] | |
|
77 | @user.destroy | |
|
78 | if @user.destroyed? | |
|
79 | logout_user | |
|
80 | flash[:notice] = l(:notice_account_deleted) | |
|
81 | end | |
|
82 | redirect_to home_path | |
|
83 | end | |
|
84 | end | |
|
85 | ||
|
68 | 86 | # Manage user's password |
|
69 | 87 | def password |
|
70 | 88 | @user = User.current |
@@ -482,6 +482,12 class User < Principal | |||
|
482 | 482 | allowed_to?(action, nil, options.reverse_merge(:global => true), &block) |
|
483 | 483 | end |
|
484 | 484 | |
|
485 | # Returns true if the user is allowed to delete his own account | |
|
486 | def own_account_deletable? | |
|
487 | Setting.unsubscribe? && | |
|
488 | (!admin? || User.active.first(:conditions => ["admin = ? AND id <> ?", true, id]).present?) | |
|
489 | end | |
|
490 | ||
|
485 | 491 | safe_attributes 'login', |
|
486 | 492 | 'firstname', |
|
487 | 493 | 'lastname', |
@@ -3,6 +3,9 | |||
|
3 | 3 | <p><%=l(:field_login)%>: <strong><%= link_to_user(@user, :format => :username) %></strong><br /> |
|
4 | 4 | <%=l(:field_created_on)%>: <%= format_time(@user.created_on) %></p> |
|
5 | 5 | |
|
6 | <% if @user.own_account_deletable? %> | |
|
7 | <p><%= link_to(l(:button_delete_my_account), {:action => 'destroy'}, :class => 'icon icon-del') %></p> | |
|
8 | <% end %> | |
|
6 | 9 | |
|
7 | 10 | <h4><%= l(:label_feeds_access_key) %></h4> |
|
8 | 11 |
@@ -10,6 +10,8 | |||
|
10 | 10 | [l(:label_registration_manual_activation), "2"], |
|
11 | 11 | [l(:label_registration_automatic_activation), "3"]] %></p> |
|
12 | 12 | |
|
13 | <p><%= setting_check_box :unsubscribe %></p> | |
|
14 | ||
|
13 | 15 | <p><%= setting_text_field :password_min_length, :size => 6 %></p> |
|
14 | 16 | |
|
15 | 17 | <p><%= setting_check_box :lost_password, :label => :label_password_lost %></p> |
@@ -173,6 +173,7 en: | |||
|
173 | 173 | notice_gantt_chart_truncated: "The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})" |
|
174 | 174 | notice_issue_successful_create: "Issue %{id} created." |
|
175 | 175 | notice_issue_update_conflict: "The issue has been updated by an other user while you were editing it." |
|
176 | notice_account_deleted: "Your account has been permanently deleted." | |
|
176 | 177 | |
|
177 | 178 | error_can_t_load_default_data: "Default configuration could not be loaded: %{value}" |
|
178 | 179 | error_scm_not_found: "The entry or revision was not found in the repository." |
@@ -383,6 +384,7 en: | |||
|
383 | 384 | setting_issue_group_assignment: Allow issue assignment to groups |
|
384 | 385 | setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues |
|
385 | 386 | setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed |
|
387 | setting_unsubscribe: Allow users to unsubscribe | |
|
386 | 388 | |
|
387 | 389 | permission_add_project: Create project |
|
388 | 390 | permission_add_subprojects: Create subprojects |
@@ -894,6 +896,7 en: | |||
|
894 | 896 | button_show: Show |
|
895 | 897 | button_edit_section: Edit this section |
|
896 | 898 | button_export: Export |
|
899 | button_delete_my_account: Delete my account | |
|
897 | 900 | |
|
898 | 901 | status_active: active |
|
899 | 902 | status_registered: registered |
@@ -978,6 +981,7 en: | |||
|
978 | 981 | text_issue_conflict_resolution_overwrite: "Apply my changes anyway (previous notes will be kept but some changes may be overwritten)" |
|
979 | 982 | text_issue_conflict_resolution_add_notes: "Add my notes and discard my other changes" |
|
980 | 983 | text_issue_conflict_resolution_cancel: "Discard all my changes and redisplay %{link}" |
|
984 | text_account_destroy_confirmation: "Are you sure you want to proceed?\nYour account will be permanently deleted, with no way to reactivate it." | |
|
981 | 985 | |
|
982 | 986 | default_role_manager: Manager |
|
983 | 987 | default_role_developer: Developer |
@@ -188,6 +188,7 fr: | |||
|
188 | 188 | notice_gantt_chart_truncated: "Le diagramme a été tronqué car il excède le nombre maximal d'éléments pouvant être affichés (%{max})" |
|
189 | 189 | notice_issue_successful_create: "La demande %{id} a été créée." |
|
190 | 190 | notice_issue_update_conflict: "La demande a été mise à jour par un autre utilisateur pendant que vous la modifiez." |
|
191 | notice_account_deleted: "Votre compte a été définitivement supprimé." | |
|
191 | 192 | |
|
192 | 193 | error_can_t_load_default_data: "Une erreur s'est produite lors du chargement du paramétrage : %{value}" |
|
193 | 194 | error_scm_not_found: "L'entrée et/ou la révision demandée n'existe pas dans le dépôt." |
@@ -379,6 +380,7 fr: | |||
|
379 | 380 | setting_issue_group_assignment: Permettre l'assignement des demandes aux groupes |
|
380 | 381 | setting_default_issue_start_date_to_creation_date: Donner à la date de début d'une nouvelle demande la valeur de la date du jour |
|
381 | 382 | setting_commit_cross_project_ref: Permettre le référencement et la résolution des demandes de tous les autres projets |
|
383 | setting_unsubscribe: Permettre aux utilisateurs de se désinscrire | |
|
382 | 384 | |
|
383 | 385 | permission_add_project: Créer un projet |
|
384 | 386 | permission_add_subprojects: Créer des sous-projets |
@@ -868,6 +870,7 fr: | |||
|
868 | 870 | button_show: Afficher |
|
869 | 871 | button_edit_section: Modifier cette section |
|
870 | 872 | button_export: Exporter |
|
873 | button_delete_my_account: Supprimer mon compte | |
|
871 | 874 | |
|
872 | 875 | status_active: actif |
|
873 | 876 | status_registered: enregistré |
@@ -934,6 +937,7 fr: | |||
|
934 | 937 | text_issue_conflict_resolution_overwrite: "Appliquer quand même ma mise à jour (les notes précédentes seront conservées mais des changements pourront être écrasés)" |
|
935 | 938 | text_issue_conflict_resolution_add_notes: "Ajouter mes notes et ignorer mes autres changements" |
|
936 | 939 | text_issue_conflict_resolution_cancel: "Annuler ma mise à jour et réafficher %{link}" |
|
940 | text_account_destroy_confirmation: "Êtes-vous sûr de vouloir continuer ?\nVotre compte sera définitivement supprimé, sans aucune possibilité de le réactiver." | |
|
937 | 941 | |
|
938 | 942 | default_role_manager: "Manager " |
|
939 | 943 | default_role_developer: "Développeur " |
@@ -78,6 +78,8 ActionController::Routing::Routes.draw do |map| | |||
|
78 | 78 | |
|
79 | 79 | map.connect 'my/account', :controller => 'my', :action => 'account', |
|
80 | 80 | :conditions => {:method => [:get, :post]} |
|
81 | map.connect 'my/account/destroy', :controller => 'my', :action => 'destroy', | |
|
82 | :conditions => {:method => [:get, :post]} | |
|
81 | 83 | map.connect 'my/page', :controller => 'my', :action => 'page', |
|
82 | 84 | :conditions => {:method => :get} |
|
83 | 85 | # Redirects to my/page |
@@ -31,6 +31,8 self_registration: | |||
|
31 | 31 | default: '2' |
|
32 | 32 | lost_password: |
|
33 | 33 | default: 1 |
|
34 | unsubscribe: | |
|
35 | default: 1 | |
|
34 | 36 | password_min_length: |
|
35 | 37 | format: int |
|
36 | 38 | default: 4 |
@@ -84,6 +84,45 class MyControllerTest < ActionController::TestCase | |||
|
84 | 84 | assert user.groups.empty? |
|
85 | 85 | end |
|
86 | 86 | |
|
87 | def test_my_account_should_show_destroy_link | |
|
88 | get :account | |
|
89 | assert_select 'a[href=/my/account/destroy]' | |
|
90 | end | |
|
91 | ||
|
92 | def test_get_destroy_should_display_the_destroy_confirmation | |
|
93 | get :destroy | |
|
94 | assert_response :success | |
|
95 | assert_template 'destroy' | |
|
96 | assert_select 'form[action=/my/account/destroy]' do | |
|
97 | assert_select 'input[name=confirm]' | |
|
98 | end | |
|
99 | end | |
|
100 | ||
|
101 | def test_post_destroy_without_confirmation_should_not_destroy_account | |
|
102 | assert_no_difference 'User.count' do | |
|
103 | post :destroy | |
|
104 | end | |
|
105 | assert_response :success | |
|
106 | assert_template 'destroy' | |
|
107 | end | |
|
108 | ||
|
109 | def test_post_destroy_without_confirmation_should_destroy_account | |
|
110 | assert_difference 'User.count', -1 do | |
|
111 | post :destroy, :confirm => '1' | |
|
112 | end | |
|
113 | assert_redirected_to '/' | |
|
114 | assert_match /deleted/i, flash[:notice] | |
|
115 | end | |
|
116 | ||
|
117 | def test_post_destroy_with_unsubscribe_not_allowed_should_not_destroy_account | |
|
118 | User.any_instance.stubs(:own_account_deletable?).returns(false) | |
|
119 | ||
|
120 | assert_no_difference 'User.count' do | |
|
121 | post :destroy, :confirm => '1' | |
|
122 | end | |
|
123 | assert_redirected_to '/my/account' | |
|
124 | end | |
|
125 | ||
|
87 | 126 | def test_change_password |
|
88 | 127 | get :password |
|
89 | 128 | assert_response :success |
@@ -25,6 +25,12 class RoutingMyTest < ActionController::IntegrationTest | |||
|
25 | 25 | { :controller => 'my', :action => 'account' } |
|
26 | 26 | ) |
|
27 | 27 | end |
|
28 | ["get", "post"].each do |method| | |
|
29 | assert_routing( | |
|
30 | { :method => method, :path => "/my/account/destroy" }, | |
|
31 | { :controller => 'my', :action => 'destroy' } | |
|
32 | ) | |
|
33 | end | |
|
28 | 34 | assert_routing( |
|
29 | 35 | { :method => 'get', :path => "/my/page" }, |
|
30 | 36 | { :controller => 'my', :action => 'page' } |
@@ -770,7 +770,34 class UserTest < ActiveSupport::TestCase | |||
|
770 | 770 | user.auth_source = denied_auth_source |
|
771 | 771 | assert !user.change_password_allowed?, "User allowed to change password, though auth source does not" |
|
772 | 772 | end |
|
773 | end | |
|
774 | ||
|
775 | def test_own_account_deletable_should_be_true_with_unsubscrive_enabled | |
|
776 | with_settings :unsubscribe => '1' do | |
|
777 | assert_equal true, User.find(2).own_account_deletable? | |
|
778 | end | |
|
779 | end | |
|
780 | ||
|
781 | def test_own_account_deletable_should_be_false_with_unsubscrive_disabled | |
|
782 | with_settings :unsubscribe => '0' do | |
|
783 | assert_equal false, User.find(2).own_account_deletable? | |
|
784 | end | |
|
785 | end | |
|
773 | 786 | |
|
787 | def test_own_account_deletable_should_be_false_for_a_single_admin | |
|
788 | User.delete_all(["admin = ? AND id <> ?", true, 1]) | |
|
789 | ||
|
790 | with_settings :unsubscribe => '1' do | |
|
791 | assert_equal false, User.find(1).own_account_deletable? | |
|
792 | end | |
|
793 | end | |
|
794 | ||
|
795 | def test_own_account_deletable_should_be_true_for_an_admin_if_other_admin_exists | |
|
796 | User.generate_with_protected(:admin => true) | |
|
797 | ||
|
798 | with_settings :unsubscribe => '1' do | |
|
799 | assert_equal true, User.find(1).own_account_deletable? | |
|
800 | end | |
|
774 | 801 | end |
|
775 | 802 | |
|
776 | 803 | context "#allowed_to?" do |
General Comments 0
You need to be logged in to leave comments.
Login now