@@ -0,0 +1,10 | |||
|
1 | <h2><%= l :label_api_access_key %></h2> | |
|
2 | ||
|
3 | <div class="box"> | |
|
4 | <pre><%= @user.api_key %></pre> | |
|
5 | </div> | |
|
6 | ||
|
7 | <p><%= link_to l(:button_back), action: 'account' %></p> | |
|
8 | ||
|
9 | ||
|
10 |
@@ -0,0 +1,1 | |||
|
1 | $('#api-access-key').html('<%= escape_javascript @user.api_key %>').toggle(); |
@@ -0,0 +1,19 | |||
|
1 | <h3 class="title"><%= l(:label_password_required) %></h3> | |
|
2 | <%= form_tag({}, remote: true) do %> | |
|
3 | ||
|
4 | <%= hidden_field_tag '_method', request.request_method %> | |
|
5 | <%= hash_to_hidden_fields @sudo_form.original_fields %> | |
|
6 | <%= render_flash_messages %> | |
|
7 | <div class="box tabular"> | |
|
8 | <p> | |
|
9 | <label for="sudo_password"><%= l :field_password %><span class="required">*</span></label> | |
|
10 | <%= password_field_tag :sudo_password, nil, size: 25 %> | |
|
11 | </p> | |
|
12 | </div> | |
|
13 | ||
|
14 | <p class="buttons"> | |
|
15 | <%= submit_tag l(:button_confirm_password), onclick: "hideModal(this);" %> | |
|
16 | <%= submit_tag l(:button_cancel), name: nil, onclick: "hideModal(this);", type: 'button' %> | |
|
17 | </p> | |
|
18 | <% end %> | |
|
19 |
@@ -0,0 +1,17 | |||
|
1 | <h2><%= l :label_password_required %></h2> | |
|
2 | <%= form_tag({}, class: 'tabular') do %> | |
|
3 | ||
|
4 | <%= hidden_field_tag '_method', request.request_method %> | |
|
5 | <%= hash_to_hidden_fields @sudo_form.original_fields %> | |
|
6 | ||
|
7 | <div class="box"> | |
|
8 | <p> | |
|
9 | <label for="sudo_password"><%= l :field_password %><span class="required">*</span></label> | |
|
10 | <%= password_field_tag :sudo_password, nil, size: 25 %> | |
|
11 | </p> | |
|
12 | </div> | |
|
13 | <%= submit_tag l(:button_confirm_password) %> | |
|
14 | <% end %> | |
|
15 | <%= javascript_tag "$('#sudo_password').focus();" %> | |
|
16 | ||
|
17 |
@@ -0,0 +1,4 | |||
|
1 | $('#ajax-modal').html('<%= escape_javascript render partial: 'sudo_mode/new_modal' %>'); | |
|
2 | showModal('ajax-modal', '400px'); | |
|
3 | $('#sudo_password').focus(); | |
|
4 |
@@ -0,0 +1,224 | |||
|
1 | require 'active_support/core_ext/object/to_query' | |
|
2 | require 'rack/utils' | |
|
3 | ||
|
4 | module Redmine | |
|
5 | module SudoMode | |
|
6 | ||
|
7 | # timespan after which sudo mode expires when unused. | |
|
8 | MAX_INACTIVITY = 15.minutes | |
|
9 | ||
|
10 | ||
|
11 | class SudoRequired < StandardError | |
|
12 | end | |
|
13 | ||
|
14 | ||
|
15 | class Form | |
|
16 | include ActiveModel::Validations | |
|
17 | ||
|
18 | attr_accessor :password, :original_fields | |
|
19 | validate :check_password | |
|
20 | ||
|
21 | def initialize(password = nil) | |
|
22 | self.password = password | |
|
23 | end | |
|
24 | ||
|
25 | def check_password | |
|
26 | unless password.present? && User.current.check_password?(password) | |
|
27 | errors[:password] << :invalid | |
|
28 | end | |
|
29 | end | |
|
30 | end | |
|
31 | ||
|
32 | ||
|
33 | module Helper | |
|
34 | # Represents params data from hash as hidden fields | |
|
35 | # | |
|
36 | # taken from https://github.com/brianhempel/hash_to_hidden_fields | |
|
37 | def hash_to_hidden_fields(hash) | |
|
38 | cleaned_hash = hash.reject { |k, v| v.nil? } | |
|
39 | pairs = cleaned_hash.to_query.split(Rack::Utils::DEFAULT_SEP) | |
|
40 | tags = pairs.map do |pair| | |
|
41 | key, value = pair.split('=', 2).map { |str| Rack::Utils.unescape(str) } | |
|
42 | hidden_field_tag(key, value) | |
|
43 | end | |
|
44 | tags.join("\n").html_safe | |
|
45 | end | |
|
46 | end | |
|
47 | ||
|
48 | ||
|
49 | module Controller | |
|
50 | extend ActiveSupport::Concern | |
|
51 | ||
|
52 | included do | |
|
53 | around_filter :sudo_mode | |
|
54 | end | |
|
55 | ||
|
56 | # Sudo mode Around Filter | |
|
57 | # | |
|
58 | # Checks the 'last used' timestamp from session and sets the | |
|
59 | # SudoMode::active? flag accordingly. | |
|
60 | # | |
|
61 | # After the request refreshes the timestamp if sudo mode was used during | |
|
62 | # this request. | |
|
63 | def sudo_mode | |
|
64 | if api_request? | |
|
65 | SudoMode.disable! | |
|
66 | elsif sudo_timestamp_valid? | |
|
67 | SudoMode.active! | |
|
68 | end | |
|
69 | yield | |
|
70 | update_sudo_timestamp! if SudoMode.was_used? | |
|
71 | end | |
|
72 | ||
|
73 | # This renders the sudo mode form / handles sudo form submission. | |
|
74 | # | |
|
75 | # Call this method in controller actions if sudo permissions are required | |
|
76 | # for processing this request. This approach is good in cases where the | |
|
77 | # action needs to be protected in any case or where the check is simple. | |
|
78 | # | |
|
79 | # In cases where this decision depends on complex conditions in the model, | |
|
80 | # consider the declarative approach using the require_sudo_mode class | |
|
81 | # method and a corresponding declaration in the model that causes it to throw | |
|
82 | # a SudoRequired Error when necessary. | |
|
83 | # | |
|
84 | # All parameter names given are included as hidden fields to be resubmitted | |
|
85 | # along with the password. | |
|
86 | # | |
|
87 | # Returns true when processing the action should continue, false otherwise. | |
|
88 | # If false is returned, render has already been called for display of the | |
|
89 | # password form. | |
|
90 | # | |
|
91 | # if @user.mail_changed? | |
|
92 | # require_sudo_mode :user or return | |
|
93 | # end | |
|
94 | # | |
|
95 | def require_sudo_mode(*param_names) | |
|
96 | return true if SudoMode.active? | |
|
97 | ||
|
98 | if param_names.blank? | |
|
99 | param_names = params.keys - %w(id action controller sudo_password) | |
|
100 | end | |
|
101 | ||
|
102 | process_sudo_form | |
|
103 | ||
|
104 | if SudoMode.active? | |
|
105 | true | |
|
106 | else | |
|
107 | render_sudo_form param_names | |
|
108 | false | |
|
109 | end | |
|
110 | end | |
|
111 | ||
|
112 | # display the sudo password form | |
|
113 | def render_sudo_form(param_names) | |
|
114 | @sudo_form ||= SudoMode::Form.new | |
|
115 | @sudo_form.original_fields = params.slice( *param_names ) | |
|
116 | # a simple 'render "sudo_mode/new"' works when used directly inside an | |
|
117 | # action, but not when called from a before_filter: | |
|
118 | respond_to do |format| | |
|
119 | format.html { render 'sudo_mode/new' } | |
|
120 | format.js { render 'sudo_mode/new' } | |
|
121 | end | |
|
122 | end | |
|
123 | ||
|
124 | # handle sudo password form submit | |
|
125 | def process_sudo_form | |
|
126 | if params[:sudo_password] | |
|
127 | @sudo_form = SudoMode::Form.new(params[:sudo_password]) | |
|
128 | if @sudo_form.valid? | |
|
129 | SudoMode.active! | |
|
130 | else | |
|
131 | flash.now[:error] = l(:notice_account_wrong_password) | |
|
132 | end | |
|
133 | end | |
|
134 | end | |
|
135 | ||
|
136 | def sudo_timestamp_valid? | |
|
137 | session[:sudo_timestamp].to_i > MAX_INACTIVITY.ago.to_i | |
|
138 | end | |
|
139 | ||
|
140 | def update_sudo_timestamp!(new_value = Time.now.to_i) | |
|
141 | session[:sudo_timestamp] = new_value | |
|
142 | end | |
|
143 | ||
|
144 | # Before Filter which is used by the require_sudo_mode class method. | |
|
145 | class SudoRequestFilter < Struct.new(:parameters, :request_methods) | |
|
146 | def before(controller) | |
|
147 | method_matches = request_methods.blank? || request_methods.include?(controller.request.method_symbol) | |
|
148 | if SudoMode.possible? && method_matches | |
|
149 | controller.require_sudo_mode( *parameters ) | |
|
150 | else | |
|
151 | true | |
|
152 | end | |
|
153 | end | |
|
154 | end | |
|
155 | ||
|
156 | module ClassMethods | |
|
157 | ||
|
158 | # Handles sudo requirements for the given actions, preserving the named | |
|
159 | # parameters, or any parameters if you omit the :parameters option. | |
|
160 | # | |
|
161 | # Sudo enforcement by default is active for all requests to an action | |
|
162 | # but may be limited to a certain subset of request methods via the | |
|
163 | # :only option. | |
|
164 | # | |
|
165 | # Examples: | |
|
166 | # | |
|
167 | # require_sudo_mode :account, only: :post | |
|
168 | # require_sudo_mode :update, :create, parameters: %w(role) | |
|
169 | # require_sudo_mode :destroy | |
|
170 | # | |
|
171 | def require_sudo_mode(*args) | |
|
172 | actions = args.dup | |
|
173 | options = actions.extract_options! | |
|
174 | filter = SudoRequestFilter.new Array(options[:parameters]), Array(options[:only]) | |
|
175 | before_filter filter, only: actions | |
|
176 | end | |
|
177 | end | |
|
178 | end | |
|
179 | ||
|
180 | ||
|
181 | # true if the sudo mode state was queried during this request | |
|
182 | def self.was_used? | |
|
183 | !!RequestStore.store[:sudo_mode_was_used] | |
|
184 | end | |
|
185 | ||
|
186 | # true if sudo mode is currently active. | |
|
187 | # | |
|
188 | # Calling this method also turns was_used? to true, therefore | |
|
189 | # it is important to only call this when sudo is actually needed, as the last | |
|
190 | # condition to determine wether a change can be done or not. | |
|
191 | # | |
|
192 | # If you do it wrong, timeout of the sudo mode will happen too late or not at | |
|
193 | # all. | |
|
194 | def self.active? | |
|
195 | if !!RequestStore.store[:sudo_mode] | |
|
196 | RequestStore.store[:sudo_mode_was_used] = true | |
|
197 | end | |
|
198 | end | |
|
199 | ||
|
200 | def self.active! | |
|
201 | RequestStore.store[:sudo_mode] = true | |
|
202 | end | |
|
203 | ||
|
204 | def self.possible? | |
|
205 | !disabled? && User.current.logged? | |
|
206 | end | |
|
207 | ||
|
208 | # Turn off sudo mode (never require password entry). | |
|
209 | def self.disable! | |
|
210 | RequestStore.store[:sudo_mode_disabled] = true | |
|
211 | end | |
|
212 | ||
|
213 | # Turn sudo mode back on | |
|
214 | def self.enable! | |
|
215 | RequestStore.store[:sudo_mode_disabled] = nil | |
|
216 | end | |
|
217 | ||
|
218 | def self.disabled? | |
|
219 | !!RequestStore.store[:sudo_mode_disabled] | |
|
220 | end | |
|
221 | ||
|
222 | end | |
|
223 | end | |
|
224 |
@@ -0,0 +1,126 | |||
|
1 | require File.expand_path('../../test_helper', __FILE__) | |
|
2 | ||
|
3 | class SudoTest < Redmine::IntegrationTest | |
|
4 | fixtures :projects, :members, :member_roles, :roles, :users | |
|
5 | ||
|
6 | def setup | |
|
7 | Redmine::SudoMode.enable! | |
|
8 | end | |
|
9 | ||
|
10 | def teardown | |
|
11 | Redmine::SudoMode.disable! | |
|
12 | end | |
|
13 | ||
|
14 | def test_create_member_xhr | |
|
15 | log_user 'admin', 'admin' | |
|
16 | get '/projects/ecookbook/settings/members' | |
|
17 | assert_response :success | |
|
18 | ||
|
19 | assert_no_difference 'Member.count' do | |
|
20 | xhr :post, '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7} | |
|
21 | end | |
|
22 | ||
|
23 | assert_no_difference 'Member.count' do | |
|
24 | xhr :post, '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: '' | |
|
25 | end | |
|
26 | ||
|
27 | assert_no_difference 'Member.count' do | |
|
28 | xhr :post, '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: 'wrong' | |
|
29 | end | |
|
30 | ||
|
31 | assert_difference 'Member.count' do | |
|
32 | xhr :post, '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: 'admin' | |
|
33 | end | |
|
34 | assert User.find(7).member_of?(Project.find(1)) | |
|
35 | end | |
|
36 | ||
|
37 | def test_create_member | |
|
38 | log_user 'admin', 'admin' | |
|
39 | get '/projects/ecookbook/settings/members' | |
|
40 | assert_response :success | |
|
41 | ||
|
42 | assert_no_difference 'Member.count' do | |
|
43 | post '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7} | |
|
44 | end | |
|
45 | ||
|
46 | assert_no_difference 'Member.count' do | |
|
47 | post '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: '' | |
|
48 | end | |
|
49 | ||
|
50 | assert_no_difference 'Member.count' do | |
|
51 | post '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: 'wrong' | |
|
52 | end | |
|
53 | ||
|
54 | assert_difference 'Member.count' do | |
|
55 | post '/projects/ecookbook/memberships', membership: {role_ids: [1], user_id: 7}, sudo_password: 'admin' | |
|
56 | end | |
|
57 | ||
|
58 | assert_redirected_to '/projects/ecookbook/settings/members' | |
|
59 | assert User.find(7).member_of?(Project.find(1)) | |
|
60 | end | |
|
61 | ||
|
62 | def test_create_role | |
|
63 | log_user 'admin', 'admin' | |
|
64 | get '/roles' | |
|
65 | assert_response :success | |
|
66 | ||
|
67 | get '/roles/new' | |
|
68 | assert_response :success | |
|
69 | ||
|
70 | post '/roles', role: { } | |
|
71 | assert_response :success | |
|
72 | assert_select 'h2', 'Confirm your password to continue' | |
|
73 | assert_select 'form[action="/roles"]' | |
|
74 | assert assigns(:sudo_form).errors.blank? | |
|
75 | ||
|
76 | post '/roles', role: { name: 'new role', issues_visibility: 'all' } | |
|
77 | assert_response :success | |
|
78 | assert_select 'h2', 'Confirm your password to continue' | |
|
79 | assert_select 'form[action="/roles"]' | |
|
80 | assert_match /"new role"/, response.body | |
|
81 | assert assigns(:sudo_form).errors.blank? | |
|
82 | ||
|
83 | post '/roles', role: { name: 'new role', issues_visibility: 'all' }, sudo_password: 'wrong' | |
|
84 | assert_response :success | |
|
85 | assert_select 'h2', 'Confirm your password to continue' | |
|
86 | assert_select 'form[action="/roles"]' | |
|
87 | assert_match /"new role"/, response.body | |
|
88 | assert assigns(:sudo_form).errors[:password].present? | |
|
89 | ||
|
90 | assert_difference 'Role.count' do | |
|
91 | post '/roles', role: { name: 'new role', issues_visibility: 'all', assignable: '1', permissions: %w(view_calendar) }, sudo_password: 'admin' | |
|
92 | end | |
|
93 | assert_redirected_to '/roles' | |
|
94 | end | |
|
95 | ||
|
96 | def test_update_email_address | |
|
97 | log_user 'jsmith', 'jsmith' | |
|
98 | get '/my/account' | |
|
99 | assert_response :success | |
|
100 | post '/my/account', user: { mail: 'newmail@test.com' } | |
|
101 | assert_response :success | |
|
102 | assert_select 'h2', 'Confirm your password to continue' | |
|
103 | assert_select 'form[action="/my/account"]' | |
|
104 | assert_match /"newmail@test\.com"/, response.body | |
|
105 | assert assigns(:sudo_form).errors.blank? | |
|
106 | ||
|
107 | # wrong password | |
|
108 | post '/my/account', user: { mail: 'newmail@test.com' }, sudo_password: 'wrong' | |
|
109 | assert_response :success | |
|
110 | assert_select 'h2', 'Confirm your password to continue' | |
|
111 | assert_select 'form[action="/my/account"]' | |
|
112 | assert_match /"newmail@test\.com"/, response.body | |
|
113 | assert assigns(:sudo_form).errors[:password].present? | |
|
114 | ||
|
115 | # correct password | |
|
116 | post '/my/account', user: { mail: 'newmail@test.com' }, sudo_password: 'jsmith' | |
|
117 | assert_redirected_to '/my/account' | |
|
118 | assert_equal 'newmail@test.com', User.find_by_login('jsmith').mail | |
|
119 | ||
|
120 | # sudo mode should now be active and not require password again | |
|
121 | post '/my/account', user: { mail: 'even.newer.mail@test.com' } | |
|
122 | assert_redirected_to '/my/account' | |
|
123 | assert_equal 'even.newer.mail@test.com', User.find_by_login('jsmith').mail | |
|
124 | end | |
|
125 | ||
|
126 | end |
@@ -59,6 +59,8 class ApplicationController < ActionController::Base | |||
|
59 | 59 | include Redmine::MenuManager::MenuController |
|
60 | 60 | helper Redmine::MenuManager::MenuHelper |
|
61 | 61 | |
|
62 | include Redmine::SudoMode::Controller | |
|
63 | ||
|
62 | 64 | def session_expiration |
|
63 | 65 | if session[:user_id] |
|
64 | 66 | if session_expired? && !try_to_autologin |
@@ -21,6 +21,7 class AuthSourcesController < ApplicationController | |||
|
21 | 21 | |
|
22 | 22 | before_filter :require_admin |
|
23 | 23 | before_filter :find_auth_source, :only => [:edit, :update, :test_connection, :destroy] |
|
24 | require_sudo_mode :update, :destroy | |
|
24 | 25 | |
|
25 | 26 | def index |
|
26 | 27 | @auth_source_pages, @auth_sources = paginate AuthSource, :per_page => 25 |
@@ -18,6 +18,7 | |||
|
18 | 18 | class EmailAddressesController < ApplicationController |
|
19 | 19 | before_filter :find_user, :require_admin_or_current_user |
|
20 | 20 | before_filter :find_email_address, :only => [:update, :destroy] |
|
21 | require_sudo_mode :create, :update, :destroy | |
|
21 | 22 | |
|
22 | 23 | def index |
|
23 | 24 | @addresses = @user.email_addresses.order(:id).where(:is_default => false).to_a |
@@ -22,6 +22,8 class GroupsController < ApplicationController | |||
|
22 | 22 | before_filter :find_group, :except => [:index, :new, :create] |
|
23 | 23 | accept_api_auth :index, :show, :create, :update, :destroy, :add_users, :remove_user |
|
24 | 24 | |
|
25 | require_sudo_mode :add_users, :remove_user, :create, :update, :destroy, :edit_membership, :destroy_membership | |
|
26 | ||
|
25 | 27 | helper :custom_fields |
|
26 | 28 | helper :principal_memberships |
|
27 | 29 |
@@ -23,6 +23,8 class MembersController < ApplicationController | |||
|
23 | 23 | before_filter :authorize |
|
24 | 24 | accept_api_auth :index, :show, :create, :update, :destroy |
|
25 | 25 | |
|
26 | require_sudo_mode :create, :update, :destroy | |
|
27 | ||
|
26 | 28 | def index |
|
27 | 29 | scope = @project.memberships.active |
|
28 | 30 | @offset, @limit = api_offset_and_limit |
@@ -20,6 +20,9 class MyController < ApplicationController | |||
|
20 | 20 | # let user change user's password when user has to |
|
21 | 21 | skip_before_filter :check_password_change, :only => :password |
|
22 | 22 | |
|
23 | require_sudo_mode :account, only: :post | |
|
24 | require_sudo_mode :reset_rss_key, :reset_api_key, :show_api_key, :destroy | |
|
25 | ||
|
23 | 26 | helper :issues |
|
24 | 27 | helper :users |
|
25 | 28 | helper :custom_fields |
@@ -123,6 +126,10 class MyController < ApplicationController | |||
|
123 | 126 | redirect_to my_account_path |
|
124 | 127 | end |
|
125 | 128 | |
|
129 | def show_api_key | |
|
130 | @user = User.current | |
|
131 | end | |
|
132 | ||
|
126 | 133 | # Create a new API key |
|
127 | 134 | def reset_api_key |
|
128 | 135 | if request.post? |
@@ -25,6 +25,7 class ProjectsController < ApplicationController | |||
|
25 | 25 | before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ] |
|
26 | 26 | accept_rss_auth :index |
|
27 | 27 | accept_api_auth :index, :show, :create, :update, :destroy |
|
28 | require_sudo_mode :destroy | |
|
28 | 29 | |
|
29 | 30 | after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller| |
|
30 | 31 | if controller.request.post? |
@@ -23,6 +23,8 class RolesController < ApplicationController | |||
|
23 | 23 | before_filter :find_role, :only => [:show, :edit, :update, :destroy] |
|
24 | 24 | accept_api_auth :index, :show |
|
25 | 25 | |
|
26 | require_sudo_mode :create, :update, :destroy | |
|
27 | ||
|
26 | 28 | def index |
|
27 | 29 | respond_to do |format| |
|
28 | 30 | format.html { |
@@ -23,6 +23,8 class SettingsController < ApplicationController | |||
|
23 | 23 | |
|
24 | 24 | before_filter :require_admin |
|
25 | 25 | |
|
26 | require_sudo_mode :index, :edit, :plugin | |
|
27 | ||
|
26 | 28 | def index |
|
27 | 29 | edit |
|
28 | 30 | render :action => 'edit' |
@@ -28,6 +28,8 class UsersController < ApplicationController | |||
|
28 | 28 | include CustomFieldsHelper |
|
29 | 29 | helper :principal_memberships |
|
30 | 30 | |
|
31 | require_sudo_mode :create, :update, :destroy | |
|
32 | ||
|
31 | 33 | def index |
|
32 | 34 | sort_init 'login', 'asc' |
|
33 | 35 | sort_update %w(login firstname lastname admin created_on last_login_on) |
@@ -25,6 +25,7 module ApplicationHelper | |||
|
25 | 25 | include Redmine::I18n |
|
26 | 26 | include GravatarHelper::PublicMethods |
|
27 | 27 | include Redmine::Pagination::Helper |
|
28 | include Redmine::SudoMode::Helper | |
|
28 | 29 | |
|
29 | 30 | extend Forwardable |
|
30 | 31 | def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter |
@@ -21,8 +21,8 | |||
|
21 | 21 | <% if Setting.rest_api_enabled? %> |
|
22 | 22 | <h4><%= l(:label_api_access_key) %></h4> |
|
23 | 23 | <div> |
|
24 | <%= link_to_function(l(:button_show), "$('#api-access-key').toggle();")%> | |
|
25 |
<pre id='api-access-key' class='autoscroll'>< |
|
|
24 | <%= link_to l(:button_show), {:action => 'show_api_key'}, :remote => true %> | |
|
25 | <pre id='api-access-key' class='autoscroll'></pre> | |
|
26 | 26 | </div> |
|
27 | 27 | <%= javascript_tag("$('#api-access-key').hide();") %> |
|
28 | 28 | <p> |
@@ -163,6 +163,7 de: | |||
|
163 | 163 | button_close: Schließen |
|
164 | 164 | button_collapse_all: Alle einklappen |
|
165 | 165 | button_configure: Konfigurieren |
|
166 | button_confirm_password: Kennwort bestätigen | |
|
166 | 167 | button_copy: Kopieren |
|
167 | 168 | button_copy_and_follow: Kopieren und Ticket anzeigen |
|
168 | 169 | button_create: Anlegen |
@@ -670,6 +671,7 de: | |||
|
670 | 671 | label_overview: Übersicht |
|
671 | 672 | label_parent_revision: Vorgänger |
|
672 | 673 | label_password_lost: Kennwort vergessen |
|
674 | label_password_required: Bitte geben Sie Ihr Kennwort ein | |
|
673 | 675 | label_permissions: Berechtigungen |
|
674 | 676 | label_permissions_report: Berechtigungsübersicht |
|
675 | 677 | label_personalize_page: Diese Seite anpassen |
@@ -554,6 +554,7 en: | |||
|
554 | 554 | label_register: Register |
|
555 | 555 | label_login_with_open_id_option: or login with OpenID |
|
556 | 556 | label_password_lost: Lost password |
|
557 | label_password_required: Confirm your password to continue | |
|
557 | 558 | label_home: Home |
|
558 | 559 | label_my_page: My page |
|
559 | 560 | label_my_account: My account |
@@ -989,6 +990,7 en: | |||
|
989 | 990 | button_reset: Reset |
|
990 | 991 | button_rename: Rename |
|
991 | 992 | button_change_password: Change password |
|
993 | button_confirm_password: Confirm password | |
|
992 | 994 | button_copy: Copy |
|
993 | 995 | button_copy_and_follow: Copy and follow |
|
994 | 996 | button_annotate: Annotate |
@@ -67,6 +67,7 Rails.application.routes.draw do | |||
|
67 | 67 | match 'my', :controller => 'my', :action => 'index', :via => :get # Redirects to my/page |
|
68 | 68 | match 'my/reset_rss_key', :controller => 'my', :action => 'reset_rss_key', :via => :post |
|
69 | 69 | match 'my/reset_api_key', :controller => 'my', :action => 'reset_api_key', :via => :post |
|
70 | match 'my/show_api_key', :controller => 'my', :action => 'show_api_key', :via => :get | |
|
70 | 71 | match 'my/password', :controller => 'my', :action => 'password', :via => [:get, :post] |
|
71 | 72 | match 'my/page_layout', :controller => 'my', :action => 'page_layout', :via => :get |
|
72 | 73 | match 'my/add_block', :controller => 'my', :action => 'add_block', :via => :post |
@@ -22,6 +22,7 class AuthSourcesControllerTest < ActionController::TestCase | |||
|
22 | 22 | |
|
23 | 23 | def setup |
|
24 | 24 | @request.session[:user_id] = 1 |
|
25 | Redmine::SudoMode.disable! | |
|
25 | 26 | end |
|
26 | 27 | |
|
27 | 28 | def test_index |
@@ -22,6 +22,7 class EmailAddressesControllerTest < ActionController::TestCase | |||
|
22 | 22 | |
|
23 | 23 | def setup |
|
24 | 24 | User.current = nil |
|
25 | Redmine::SudoMode.disable! | |
|
25 | 26 | end |
|
26 | 27 | |
|
27 | 28 | def test_index_with_no_additional_emails |
@@ -22,6 +22,7 class GroupsControllerTest < ActionController::TestCase | |||
|
22 | 22 | |
|
23 | 23 | def setup |
|
24 | 24 | @request.session[:user_id] = 1 |
|
25 | Redmine::SudoMode.disable! | |
|
25 | 26 | end |
|
26 | 27 | |
|
27 | 28 | def test_index |
@@ -23,6 +23,7 class MembersControllerTest < ActionController::TestCase | |||
|
23 | 23 | def setup |
|
24 | 24 | User.current = nil |
|
25 | 25 | @request.session[:user_id] = 2 |
|
26 | Redmine::SudoMode.disable! | |
|
26 | 27 | end |
|
27 | 28 | |
|
28 | 29 | def test_new |
@@ -23,6 +23,7 class MyControllerTest < ActionController::TestCase | |||
|
23 | 23 | |
|
24 | 24 | def setup |
|
25 | 25 | @request.session[:user_id] = 2 |
|
26 | Redmine::SudoMode.disable! | |
|
26 | 27 | end |
|
27 | 28 | |
|
28 | 29 | def test_index |
@@ -253,6 +254,12 class MyControllerTest < ActionController::TestCase | |||
|
253 | 254 | assert_redirected_to '/my/account' |
|
254 | 255 | end |
|
255 | 256 | |
|
257 | def test_show_api_key | |
|
258 | get :show_api_key | |
|
259 | assert_response :success | |
|
260 | assert_select 'pre', User.find(2).api_key | |
|
261 | end | |
|
262 | ||
|
256 | 263 | def test_reset_api_key_with_existing_key |
|
257 | 264 | @previous_token_value = User.find(2).api_key # Will generate one if it's missing |
|
258 | 265 | post :reset_api_key |
@@ -28,6 +28,7 class ProjectsControllerTest < ActionController::TestCase | |||
|
28 | 28 | def setup |
|
29 | 29 | @request.session[:user_id] = nil |
|
30 | 30 | Setting.default_language = 'en' |
|
31 | Redmine::SudoMode.disable! | |
|
31 | 32 | end |
|
32 | 33 | |
|
33 | 34 | def test_index_by_anonymous_should_not_show_private_projects |
@@ -23,6 +23,7 class RolesControllerTest < ActionController::TestCase | |||
|
23 | 23 | def setup |
|
24 | 24 | User.current = nil |
|
25 | 25 | @request.session[:user_id] = 1 # admin |
|
26 | Redmine::SudoMode.disable! | |
|
26 | 27 | end |
|
27 | 28 | |
|
28 | 29 | def test_index |
@@ -24,6 +24,7 class SettingsControllerTest < ActionController::TestCase | |||
|
24 | 24 | def setup |
|
25 | 25 | User.current = nil |
|
26 | 26 | @request.session[:user_id] = 1 # admin |
|
27 | Redmine::SudoMode.disable! | |
|
27 | 28 | end |
|
28 | 29 | |
|
29 | 30 | def test_index |
@@ -30,6 +30,7 class UsersControllerTest < ActionController::TestCase | |||
|
30 | 30 | def setup |
|
31 | 31 | User.current = nil |
|
32 | 32 | @request.session[:user_id] = 1 # admin |
|
33 | Redmine::SudoMode.disable! | |
|
33 | 34 | end |
|
34 | 35 | |
|
35 | 36 | def test_index |
@@ -26,6 +26,14 class AdminTest < Redmine::IntegrationTest | |||
|
26 | 26 | :members, |
|
27 | 27 | :enabled_modules |
|
28 | 28 | |
|
29 | def setup | |
|
30 | Redmine::SudoMode.enable! | |
|
31 | end | |
|
32 | ||
|
33 | def teardown | |
|
34 | Redmine::SudoMode.disable! | |
|
35 | end | |
|
36 | ||
|
29 | 37 | def test_add_user |
|
30 | 38 | log_user("admin", "admin") |
|
31 | 39 | get "/users/new" |
@@ -36,6 +44,15 class AdminTest < Redmine::IntegrationTest | |||
|
36 | 44 | :lastname => "Smith", :mail => "psmith@somenet.foo", |
|
37 | 45 | :language => "en", :password => "psmith09", |
|
38 | 46 | :password_confirmation => "psmith09" } |
|
47 | assert_response :success | |
|
48 | assert_nil User.find_by_login("psmith") | |
|
49 | ||
|
50 | post "/users", | |
|
51 | :user => { :login => "psmith", :firstname => "Paul", | |
|
52 | :lastname => "Smith", :mail => "psmith@somenet.foo", | |
|
53 | :language => "en", :password => "psmith09", | |
|
54 | :password_confirmation => "psmith09" }, | |
|
55 | :sudo_password => 'admin' | |
|
39 | 56 | |
|
40 | 57 | user = User.find_by_login("psmith") |
|
41 | 58 | assert_kind_of User, user |
General Comments 0
You need to be logged in to leave comments.
Login now