Feature #4687 » 4687-v4_for_v5.1.3.patch
app/controllers/projects_controller.rb | ||
---|---|---|
23 | 23 |
menu_item :projects, :only => [:index, :new, :copy, :create] |
24 | 24 | |
25 | 25 |
before_action :find_project, |
26 |
:except => [:index, :autocomplete, :list, :new, :create, :copy, :bulk_destroy]
|
|
26 |
:except => [:index, :autocomplete, :list, :new, :create, :bulk_destroy] |
|
27 | 27 |
before_action :authorize, |
28 |
:except => [:index, :autocomplete, :list, :new, :create, :copy,
|
|
28 |
:except => [:index, :autocomplete, :list, :new, :create, |
|
29 | 29 |
:archive, :unarchive, |
30 | 30 |
:destroy, :bulk_destroy] |
31 | 31 |
before_action :authorize_global, :only => [:new, :create] |
32 |
before_action :require_admin, :only => [:copy, :archive, :unarchive, :bulk_destroy]
|
|
32 |
before_action :require_admin, :only => [:archive, :unarchive, :bulk_destroy] |
|
33 | 33 |
accept_atom_auth :index |
34 | 34 |
accept_api_auth :index, :show, :create, :update, :destroy, :archive, :unarchive, :close, :reopen |
35 | 35 |
require_sudo_mode :destroy, :bulk_destroy |
... | ... | |
140 | 140 |
end |
141 | 141 | |
142 | 142 |
def copy |
143 |
@project = nil # Reset because source project was set in @project for authorize. |
|
143 | 144 |
@issue_custom_fields = IssueCustomField.sorted.to_a |
144 | 145 |
@trackers = Tracker.sorted.to_a |
145 | 146 |
@source_project = Project.find(params[:id]) |
app/models/role.rb | ||
---|---|---|
82 | 82 |
validates_presence_of :name |
83 | 83 |
validates_uniqueness_of :name, :case_sensitive => true |
84 | 84 |
validates_length_of :name, :maximum => 255 |
85 |
validate :check_the_prerequisites_for_copy_project_permission |
|
86 | ||
85 | 87 |
validates_inclusion_of( |
86 | 88 |
:issues_visibility, |
87 | 89 |
:in => ISSUES_VISIBILITY_OPTIONS.collect(&:first), |
... | ... | |
325 | 327 |
role |
326 | 328 |
end |
327 | 329 |
private_class_method :find_or_create_system_role |
330 | ||
331 |
def check_the_prerequisites_for_copy_project_permission |
|
332 |
if self.permissions.include?(:copy_project) && |
|
333 |
self.permissions.exclude?(:add_project) && |
|
334 |
self.permissions.exclude?(:add_subprojects) |
|
335 |
errors.add(:base, l(:error_cannot_have_copy_project_permission)) |
|
336 |
end |
|
337 |
end |
|
328 | 338 |
end |
app/views/projects/show.html.erb | ||
---|---|---|
5 | 5 |
<% if User.current.allowed_to?(:add_subprojects, @project) %> |
6 | 6 |
<%= link_to l(:label_subproject_new), new_project_path(:parent_id => @project), :class => 'icon icon-add' %> |
7 | 7 |
<% end %> |
8 |
<% if User.current.allowed_to?(:copy_project, @project) %> |
|
9 |
<%= link_tol(:button_copy), copy_project_path(@project), :class => 'icon icon-copy' %> |
|
10 |
<% end %> |
|
8 | 11 |
<% if User.current.allowed_to?(:close_project, @project) %> |
9 | 12 |
<% if @project.active? %> |
10 | 13 |
<%= link_to l(:button_close), close_project_path(@project), :data => {:confirm => l(:text_project_close_confirmation, @project.to_s)}, :method => :post, :class => 'icon icon-lock' %> |
app/views/roles/_form.html.erb | ||
---|---|---|
60 | 60 |
<label class="floating"> |
61 | 61 |
<%= check_box_tag 'role[permissions][]', permission.name, (@role.permissions.include? permission.name), |
62 | 62 |
:id => "role_permissions_#{permission.name}", |
63 |
:data => {:shows => ".#{permission.name}_shown"} %> |
|
63 |
:data => {:shows => ".#{permission.name}_shown" }, |
|
64 |
:disabled => (true if permission.name == :copy_project && !@role.permissions.include?(:add_project) && !@role.permissions.include?(:add_subprojects)) %> |
|
64 | 65 |
<%= l_or_humanize(permission.name, :prefix => 'permission_') %> |
65 | 66 |
</label> |
66 | 67 |
<% end %> |
config/locales/de.yml | ||
---|---|---|
906 | 906 |
permission_add_issue_notes: Kommentare hinzufügen |
907 | 907 |
permission_add_issue_watchers: Beobachter hinzufügen |
908 | 908 |
permission_add_issues: Tickets hinzufügen |
909 |
permission_copy_project: Projekt kopieren |
|
909 | 910 |
permission_add_messages: Forenbeiträge hinzufügen |
910 | 911 |
permission_add_project: Projekt erstellen |
911 | 912 |
permission_add_subprojects: Unterprojekte erstellen |
config/locales/en.yml | ||
---|---|---|
245 | 245 |
error_attachment_not_found: "Attachment %{name} not found" |
246 | 246 |
error_invalid_authenticity_token: "Invalid form authenticity token." |
247 | 247 |
error_query_statement_invalid: "An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator." |
248 |
error_cannot_have_copy_project_permission: "Can't have copy_project permission without add_project permission or add_subprojects permission." |
|
248 | 249 | |
249 | 250 |
mail_subject_lost_password: "Your %{value} password" |
250 | 251 |
mail_body_lost_password: 'To change your password, click on the following link:' |
lib/redmine/preparation.rb | ||
---|---|---|
45 | 45 |
map.permission :manage_members, {:projects => :settings, :members => [:index, :show, :new, :create, :edit, :update, :destroy, :autocomplete]}, :require => :member |
46 | 46 |
map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member |
47 | 47 |
map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member |
48 |
map.permission :copy_project, {:projects => [:copy]}, :require => :member |
|
48 | 49 |
# Queries |
49 | 50 |
map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member |
50 | 51 |
map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin |
public/javascripts/application.js | ||
---|---|---|
970 | 970 |
event.preventDefault(); |
971 | 971 |
} |
972 | 972 | |
973 |
function toggleCopyProjectCheckboxInit() { |
|
974 |
$('input#role_permissions_add_project, input#role_permissions_add_subprojects').change(function () { |
|
975 |
if (['input#role_permissions_add_project', 'input#role_permissions_add_subprojects'].some(el => $(el).is(':checked'))) { |
|
976 |
$('input#role_permissions_copy_project').attr('disabled', false) |
|
977 |
} else { |
|
978 |
$('input#role_permissions_copy_project').attr('disabled', true) |
|
979 |
} |
|
980 |
}); |
|
981 |
} |
|
982 | ||
973 | 983 |
function toggleDisabledOnChange() { |
974 | 984 |
var checked = $(this).is(':checked'); |
975 | 985 |
$($(this).data('disables')).attr('disabled', checked); |
... | ... | |
1027 | 1037 |
$(document).ready(function(){ |
1028 | 1038 |
$('#content').on('change', 'input[data-disables], input[data-enables], input[data-shows]', toggleDisabledOnChange); |
1029 | 1039 |
toggleDisabledInit(); |
1040 |
toggleCopyProjectCheckboxInit(); |
|
1030 | 1041 | |
1031 | 1042 |
$('#content').on('click', '.toggle-multiselect', function() { |
1032 | 1043 |
toggleMultiSelect($(this).siblings('select')); |
test/functional/projects_controller_test.rb | ||
---|---|---|
1390 | 1390 |
end |
1391 | 1391 |
end |
1392 | 1392 | |
1393 |
def test_get_copy |
|
1393 |
def test_get_copy_by_admin_user
|
|
1394 | 1394 |
@request.session[:user_id] = 1 # admin |
1395 |
orig = Project.find(1) # Login user is no member |
|
1396 |
get(:copy, :params => {:id => orig.id}) |
|
1397 |
assert_response :success |
|
1398 | ||
1399 |
assert_select 'textarea[name=?]', 'project[description]', :text => orig.description |
|
1400 |
assert_select 'input[name=?][value=?]', 'project[enabled_module_names][]', 'issue_tracking', 1 |
|
1401 |
end |
|
1402 | ||
1403 |
def test_get_copy_by_non_admin_user_with_copy_project_permission |
|
1404 |
@request.session[:user_id] = 3 |
|
1405 |
Role.find(2).add_permission!(:copy_project, :add_project) |
|
1395 | 1406 |
orig = Project.find(1) |
1396 | 1407 |
get(:copy, :params => {:id => orig.id}) |
1397 | 1408 |
assert_response :success |
... | ... | |
1400 | 1411 |
assert_select 'input[name=?][value=?]', 'project[enabled_module_names][]', 'issue_tracking', 1 |
1401 | 1412 |
end |
1402 | 1413 | |
1414 |
def test_get_copy_by_non_admin_user_without_copy_project_permission_should_respond_with_403 |
|
1415 |
@request.session[:user_id] = 3 |
|
1416 |
Role.find(2).remove_permission! :copy_project |
|
1417 |
orig = Project.find(1) |
|
1418 |
get(:copy, :params => {:id => orig.id}) |
|
1419 |
assert_response 403 |
|
1420 |
end |
|
1421 | ||
1403 | 1422 |
def test_get_copy_with_invalid_source_should_respond_with_404 |
1404 | 1423 |
@request.session[:user_id] = 1 |
1405 | 1424 |
get(:copy, :params => {:id => 99}) |
... | ... | |
1446 | 1465 |
assert_equal 0, project.members.count |
1447 | 1466 |
end |
1448 | 1467 | |
1468 |
def test_post_copy_by_non_admin_user_with_copy_project_and_add_project_permission |
|
1469 |
@request.session[:user_id] = 3 |
|
1470 |
Role.find(2).add_permission!(:copy_project, :add_project) |
|
1471 |
CustomField.delete_all |
|
1472 | ||
1473 |
assert_difference 'Project.count' do |
|
1474 |
post( |
|
1475 |
:copy, |
|
1476 |
:params => { |
|
1477 |
:id => 1, |
|
1478 |
:project => { |
|
1479 |
:name => 'Copy', |
|
1480 |
:identifier => 'unique-copy', |
|
1481 |
:tracker_ids => ['1', '2', '3', ''], |
|
1482 |
:enabled_module_names => %w(issue_tracking time_tracking) |
|
1483 |
}, |
|
1484 |
:only => %w(issues versions) |
|
1485 |
} |
|
1486 |
) |
|
1487 |
end |
|
1488 |
project = Project.find('unique-copy') |
|
1489 |
source = Project.find(1) |
|
1490 |
assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort |
|
1491 | ||
1492 |
assert_equal source.versions.count, project.versions.count, "All versions were not copied" |
|
1493 |
assert_equal source.issues.count, project.issues.count, "All issues were not copied" |
|
1494 |
assert_equal 0, project.members.count |
|
1495 |
end |
|
1496 | ||
1497 |
def test_post_copy_by_non_admin_user_with_copy_project_and_add_subprojects_permission |
|
1498 |
@request.session[:user_id] = 3 |
|
1499 |
Role.find(2).add_permission!(:copy_project, :add_subprojects) |
|
1500 |
CustomField.delete_all |
|
1501 | ||
1502 |
assert_difference 'Project.count' do |
|
1503 |
post( |
|
1504 |
:copy, |
|
1505 |
:params => { |
|
1506 |
:id => 1, |
|
1507 |
:project => { |
|
1508 |
:name => 'Copy', |
|
1509 |
:identifier => 'unique-copy', |
|
1510 |
:tracker_ids => ['1', '2', '3', ''], |
|
1511 |
:enabled_module_names => %w(issue_tracking time_tracking), |
|
1512 |
:parent_id => 1 |
|
1513 |
}, |
|
1514 |
:only => %w(issues versions) |
|
1515 |
} |
|
1516 |
) |
|
1517 |
end |
|
1518 |
project = Project.find('unique-copy') |
|
1519 |
source = Project.find(1) |
|
1520 |
assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort |
|
1521 |
assert_equal source, project.parent |
|
1522 | ||
1523 |
assert_equal source.versions.count, project.versions.count, "All versions were not copied" |
|
1524 |
assert_equal source.issues.count, project.issues.count, "All issues were not copied" |
|
1525 |
assert_equal 0, project.members.count |
|
1526 |
end |
|
1527 | ||
1449 | 1528 |
def test_post_copy_should_redirect_to_settings_when_successful |
1450 | 1529 |
@request.session[:user_id] = 1 # admin |
1451 | 1530 |
post( |
test/unit/role_test.rb | ||
---|---|---|
22 | 22 |
class RoleTest < ActiveSupport::TestCase |
23 | 23 |
fixtures :roles, :workflows, :trackers, :users |
24 | 24 | |
25 |
include Redmine::I18n |
|
26 | ||
25 | 27 |
def setup |
26 | 28 |
User.current = nil |
27 | 29 |
end |
... | ... | |
241 | 243 |
assert_nil ActiveRecord::Base.connection.select_value("SELECT 1 FROM queries_roles WHERE role_id = #{role.id}") |
242 | 244 |
assert [1, 3], query.roles |
243 | 245 |
end |
246 | ||
247 |
def test_check_the_prerequisites_for_copy_project_permission |
|
248 |
role = Role.find(2) |
|
249 |
role.remove_permission!(:copy_project, :add_project, :add_subprojects) |
|
250 | ||
251 |
role.permissions = [:copy_project] |
|
252 |
assert_not role.valid? |
|
253 |
assert_equal l(:error_cannot_have_copy_project_permission), role.errors.messages[:base].first |
|
254 | ||
255 |
role.permissions = [:copy_project, :add_project] |
|
256 |
assert role.valid? |
|
257 | ||
258 |
role.permissions = [:copy_project, :add_subprojects] |
|
259 |
assert role.valid? |
|
260 |
end |
|
244 | 261 |
end |
- « Previous
- 1
- …
- 6
- 7
- 8
- Next »