Patch by Takenori TAKAKI. git-svn-id: http://svn.redmine.org/redmine/trunk@19799 e93f8b46-1217-0410-a6f0-8f06a7374b81tags/4.2.0
} | } | ||||
end | end | ||||
def render_if_exist(options = {}, locals = {}, &block) | |||||
if options[:partial] | |||||
if lookup_context.exists?(options[:partial], lookup_context.prefixes, true) | |||||
render(options, locals, &block) | |||||
end | |||||
else | |||||
render(options, locals, &block) | |||||
end | |||||
end | |||||
private | private | ||||
def wiki_helper | def wiki_helper |
# frozen_string_literal: true | |||||
# Redmine - project management software | |||||
# Copyright (C) 2006-2020 Jean-Philippe Lang | |||||
# | |||||
# This program is free software; you can redistribute it and/or | |||||
# modify it under the terms of the GNU General Public License | |||||
# as published by the Free Software Foundation; either version 2 | |||||
# of the License, or (at your option) any later version. | |||||
# | |||||
# This program is distributed in the hope that it will be useful, | |||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
# GNU General Public License for more details. | |||||
# | |||||
# You should have received a copy of the GNU General Public License | |||||
# along with this program; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
class UserImport < Import | |||||
AUTO_MAPPABLE_FIELDS = { | |||||
'login' => 'field_login', | |||||
'firstname' => 'field_firstname', | |||||
'lastname' => 'field_lastname', | |||||
'mail' => 'field_mail', | |||||
'language' => 'field_language', | |||||
'admin' => 'field_admin', | |||||
'auth_source' => 'field_auth_source', | |||||
'password' => 'field_password', | |||||
'must_change_passwd' => 'field_must_change_passwd', | |||||
'status' => 'field_status' | |||||
} | |||||
def self.menu_item | |||||
:users | |||||
end | |||||
def self.layout | |||||
'admin' | |||||
end | |||||
def self.authorized?(user) | |||||
user.admin? | |||||
end | |||||
# Returns the objects that were imported | |||||
def saved_objects | |||||
User.where(:id => saved_items.pluck(:obj_id)).order(:id) | |||||
end | |||||
def mappable_custom_fields | |||||
UserCustomField.all | |||||
end | |||||
private | |||||
def build_object(row, item) | |||||
object = User.new | |||||
attributes = { | |||||
:login => row_value(row, 'login'), | |||||
:firstname => row_value(row, 'firstname'), | |||||
:lastname => row_value(row, 'lastname'), | |||||
:mail => row_value(row, 'mail') | |||||
} | |||||
lang = nil | |||||
if language = row_value(row, 'language') | |||||
lang = find_language(language) | |||||
end | |||||
attributes[:language] = lang || Setting.default_language | |||||
if admin = row_value(row, 'admin') | |||||
if yes?(admin) | |||||
attributes['admin'] = '1' | |||||
end | |||||
end | |||||
if auth_source_name = row_value(row, 'auth_source') | |||||
if auth_source = AuthSource.find_by(:name => auth_source_name) | |||||
attributes[:auth_source_id] = auth_source.id | |||||
end | |||||
end | |||||
if password = row_value(row, 'password') | |||||
object.password = password | |||||
object.password_confirmation = password | |||||
end | |||||
if must_change_passwd = row_value(row, 'must_change_passwd') | |||||
if yes?(must_change_passwd) | |||||
attributes[:must_change_passwd] = '1' | |||||
end | |||||
end | |||||
if status_name = row_value(row, 'status') | |||||
if status = User::LABEL_BY_STATUS.key(status_name) | |||||
attributes[:status] = status | |||||
end | |||||
end | |||||
attributes['custom_field_values'] = object.custom_field_values.each_with_object({}) do |v, h| | |||||
value = | |||||
case v.custom_field.field_format | |||||
when 'date' | |||||
row_date(row, "cf_#{v.custom_field.id}") | |||||
else | |||||
row_value(row, "cf_#{v.custom_field.id}") | |||||
end | |||||
if value | |||||
h[v.custom_field.id.to_s] = v.custom_field.value_from_keyword(value, object) | |||||
end | |||||
end | |||||
object.send(:safe_attributes=, attributes, user) | |||||
object | |||||
end | |||||
end |
<div class="splitcontent"> | |||||
<div class="splitcontentleft"> | |||||
<p> | |||||
<label for="import_mapping_login"><%= l(:field_login) %></label> | |||||
<%= mapping_select_tag @import, 'login', :required => true %> | |||||
</p> | |||||
<p> | |||||
<label for="import_mapping_firstname"><%= l(:field_firstname) %></label> | |||||
<%= mapping_select_tag @import, 'firstname', :required => true %> | |||||
</p> | |||||
<p> | |||||
<label for="import_mapping_lastname"><%= l(:field_lastname) %></label> | |||||
<%= mapping_select_tag @import, 'lastname', :required => true %> | |||||
</p> | |||||
<p> | |||||
<label for="import_mapping_mail"><%= l(:field_mail) %></label> | |||||
<%= mapping_select_tag @import, 'mail' %> | |||||
</p> | |||||
<p> | |||||
<label for="import_mapping_language"><%= l(:field_language) %></label> | |||||
<%= mapping_select_tag @import, 'language' %> | |||||
</p> | |||||
<p> | |||||
<label for="import_mapping_admin"><%= l(:field_admin) %></label> | |||||
<%= mapping_select_tag @import, 'admin' %> | |||||
</p> | |||||
<p> | |||||
<label for="import_mapping_auth_source_id"><%= l(:field_auth_source) %></label> | |||||
<%= mapping_select_tag @import, 'auth_source' %> | |||||
</p> | |||||
<p> | |||||
<label for="import_mapping_password"><%= l(:field_password) %></label> | |||||
<%= mapping_select_tag @import, 'password' %> | |||||
</p> | |||||
<p> | |||||
<label for="import_mapping_must_change_passwd"><%= l(:field_must_change_passwd) %></label> | |||||
<%= mapping_select_tag @import, 'must_change_passwd' %> | |||||
</p> | |||||
<p> | |||||
<label for="import_mapping_status"><%= l(:field_status) %></label> | |||||
<%= mapping_select_tag @import, 'status' %> | |||||
</p> | |||||
</div> | |||||
<div class="splitcontentright"> | |||||
<% @custom_fields.each do |field| %> | |||||
<p> | |||||
<label for="import_mapping_cf_<%= field.id %>"><%= field.name %></label> | |||||
<%= mapping_select_tag @import, "cf_#{field.id}", :required => field.is_required? %> | |||||
</p> | |||||
<% end %> | |||||
</div> | |||||
</div> |
<fieldset class="box tabular"> | |||||
<legend><%= l(:label_fields_mapping) %></legend> | |||||
<div id="fields-mapping"> | |||||
<%= render :partial => 'users_fields_mapping' %> | |||||
</div> | |||||
</fieldset> |
$('#fields-mapping').html('<%= escape_javascript(render :partial => 'users_fields_mapping') %>'); |
<table id="saved-items" class="list"> | |||||
<thead> | |||||
<tr> | |||||
<th><%= t(:field_login) %></th> | |||||
<th><%= t(:field_firstname) %></th> | |||||
<th><%= t(:field_lastname) %></th> | |||||
<th><%= t(:field_mail) %></th> | |||||
<th><%= t(:field_admin) %></th> | |||||
<th><%= t(:field_status) %></th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<% saved_objects.each do |user| %> | |||||
<tr> | |||||
<td><%= avatar(user, :size => "14") %><%= link_to user.login, edit_user_path(user) %></td> | |||||
<td><%= user.firstname %></td> | |||||
<td><%= user.lastname %></td> | |||||
<td><%= mail_to(user.mail) %></td> | |||||
<td><%= checked_image user.admin? %></td> | |||||
<td><%= l(("status_#{User::LABEL_BY_STATUS[user.status]}")) %> | |||||
</tr> | |||||
<% end %> | |||||
</tbody> | |||||
</table> |
</p> | </p> | ||||
<% end %> | <% end %> | ||||
<%= render :partial => "#{import_partial_prefix}_sidebar" %> | |||||
<%= render_if_exist :partial => "#{import_partial_prefix}_sidebar" %> | |||||
<%= javascript_tag do %> | <%= javascript_tag do %> | ||||
$(document).ready(function() { | $(document).ready(function() { |
<p><%= submit_tag l(:label_next).html_safe + " »".html_safe, :name => nil %></p> | <p><%= submit_tag l(:label_next).html_safe + " »".html_safe, :name => nil %></p> | ||||
<% end %> | <% end %> | ||||
<%= render :partial => "#{import_partial_prefix}_sidebar" %> | |||||
<%= render_if_exist :partial => "#{import_partial_prefix}_sidebar" %> |
<div id="import-progress"><div id="progress-label">0 / <%= @import.total_items.to_i %></div></div> | <div id="import-progress"><div id="progress-label">0 / <%= @import.total_items.to_i %></div></div> | ||||
</div> | </div> | ||||
<%= render :partial => "#{import_partial_prefix}_sidebar" %> | |||||
<%= render_if_exist :partial => "#{import_partial_prefix}_sidebar" %> | |||||
<%= javascript_tag do %> | <%= javascript_tag do %> | ||||
$(document).ready(function() { | $(document).ready(function() { |
<p><%= submit_tag l(:label_next).html_safe + " »".html_safe, :name => nil %></p> | <p><%= submit_tag l(:label_next).html_safe + " »".html_safe, :name => nil %></p> | ||||
<% end %> | <% end %> | ||||
<%= render :partial => "#{import_partial_prefix}_sidebar" %> | |||||
<%= render_if_exist :partial => "#{import_partial_prefix}_sidebar" %> |
</table> | </table> | ||||
<% end %> | <% end %> | ||||
<%= render :partial => "#{import_partial_prefix}_sidebar" %> | |||||
<%= render_if_exist :partial => "#{import_partial_prefix}_sidebar" %> |
<div class="contextual"> | <div class="contextual"> | ||||
<%= link_to l(:label_user_new), new_user_path, :class => 'icon icon-add' %> | <%= link_to l(:label_user_new), new_user_path, :class => 'icon icon-add' %> | ||||
<%= actions_dropdown do %> | |||||
<% if User.current.allowed_to?(:import_users, nil, :global => true) %> | |||||
<%= link_to l(:button_import), new_users_import_path, :class => 'icon icon-import' %> | |||||
<% end %> | |||||
<% end %> | |||||
</div> | </div> | ||||
<h2><%=l(:label_user_plural)%></h2> | <h2><%=l(:label_user_plural)%></h2> |
text_project_is_public_non_member: Public projects and their contents are available to all logged-in users. | text_project_is_public_non_member: Public projects and their contents are available to all logged-in users. | ||||
text_project_is_public_anonymous: Public projects and their contents are openly available on the network. | text_project_is_public_anonymous: Public projects and their contents are openly available on the network. | ||||
label_import_time_entries: Import time entries | label_import_time_entries: Import time entries | ||||
label_import_users: Import users |
get '/issues/imports/new', :to => 'imports#new', :defaults => { :type => 'IssueImport' }, :as => 'new_issues_import' | get '/issues/imports/new', :to => 'imports#new', :defaults => { :type => 'IssueImport' }, :as => 'new_issues_import' | ||||
get '/time_entries/imports/new', :to => 'imports#new', :defaults => { :type => 'TimeEntryImport' }, :as => 'new_time_entries_import' | get '/time_entries/imports/new', :to => 'imports#new', :defaults => { :type => 'TimeEntryImport' }, :as => 'new_time_entries_import' | ||||
get '/users/imports/new', :to => 'imports#new', :defaults => { :type => 'UserImport' }, :as => 'new_users_import' | |||||
post '/imports', :to => 'imports#create', :as => 'imports' | post '/imports', :to => 'imports#create', :as => 'imports' | ||||
get '/imports/:id', :to => 'imports#show', :as => 'import' | get '/imports/:id', :to => 'imports#show', :as => 'import' | ||||
match '/imports/:id/settings', :to => 'imports#settings', :via => [:get, :post], :as => 'import_settings' | match '/imports/:id/settings', :to => 'imports#settings', :via => [:get, :post], :as => 'import_settings' |
row;login;firstname;lastname;mail;language;admin;auth_source;password;must_change_passwd;status;phone_number | |||||
1;user1;One;CSV;user1@somenet.foo;en;yes;;password;yes;active;000-1111-2222 | |||||
2;user2;Two;Import;user2@somenet.foo;ja;no;;password;no;locked;333-4444-5555 | |||||
3;user3;Three;User;user3@somenet.foo;-;no;LDAP test server;password;no;registered;666-7777-8888 |
partial html |
assert_match(/name="new_issue-[a-z0-9]{8}"/, labelled_form_for(Issue.new){}) | assert_match(/name="new_issue-[a-z0-9]{8}"/, labelled_form_for(Issue.new){}) | ||||
end | end | ||||
def test_redner_if_exist_should_be_render_partial | |||||
controller.prepend_view_path "test/fixtures/views" | |||||
assert_equal "partial html\n", render_if_exist(:partial => 'partial') | |||||
end | |||||
def test_redner_if_exist_should_be_render_nil | |||||
controller.prepend_view_path "test/fixtures/views" | |||||
assert_nil render_if_exist(:partial => 'non_exist_partial') | |||||
end | |||||
private | private | ||||
def wiki_links_with_special_characters | def wiki_links_with_special_characters |
# frozen_string_literal: true | |||||
# Redmine - project management software | |||||
# Copyright (C) 2006-2020 Jean-Philippe Lang | |||||
# | |||||
# This program is free software; you can redistribute it and/or | |||||
# modify it under the terms of the GNU General Public License | |||||
# as published by the Free Software Foundation; either version 2 | |||||
# of the License, or (at your option) any later version. | |||||
# | |||||
# This program is distributed in the hope that it will be useful, | |||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
# GNU General Public License for more details. | |||||
# | |||||
# You should have received a copy of the GNU General Public License | |||||
# along with this program; if not, write to the Free Software | |||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
require File.expand_path('../../test_helper', __FILE__) | |||||
class UserImportTest < ActiveSupport::TestCase | |||||
include Redmine::I18n | |||||
def setup | |||||
set_language_if_valid 'en' | |||||
User.current = nil | |||||
end | |||||
def test_authorized | |||||
assert UserImport.authorized?(User.find(1)) # admins | |||||
assert !UserImport.authorized?(User.find(2)) # dose not admin | |||||
assert !UserImport.authorized?(User.find(6)) # dows not admin | |||||
end | |||||
def test_maps_login | |||||
import = generate_import_with_mapping | |||||
first, second, third = new_records(User, 3) { import.run } | |||||
assert_equal 'user1', first.login | |||||
assert_equal 'user2', second.login | |||||
assert_equal 'user3', third.login | |||||
end | |||||
def test_maps_firstname | |||||
import = generate_import_with_mapping | |||||
first, second, third = new_records(User, 3) { import.run } | |||||
assert_equal 'One', first.firstname | |||||
assert_equal 'Two', second.firstname | |||||
assert_equal 'Three', third.firstname | |||||
end | |||||
def test_maps_lastname | |||||
import = generate_import_with_mapping | |||||
first, second, third = new_records(User, 3) { import.run } | |||||
assert_equal 'CSV', first.lastname | |||||
assert_equal 'Import', second.lastname | |||||
assert_equal 'User', third.lastname | |||||
end | |||||
def test_maps_mail | |||||
import = generate_import_with_mapping | |||||
first, second, third = new_records(User, 3) { import.run } | |||||
assert_equal 'user1@somenet.foo', first.mail | |||||
assert_equal 'user2@somenet.foo', second.mail | |||||
assert_equal 'user3@somenet.foo', third.mail | |||||
end | |||||
def test_maps_language | |||||
default_language = 'fr' | |||||
with_settings :default_language => default_language do | |||||
import = generate_import_with_mapping | |||||
first, second, third = new_records(User, 3) { import.run } | |||||
assert_equal 'en', first.language | |||||
assert_equal 'ja', second.language | |||||
assert_equal default_language, third.language | |||||
end | |||||
end | |||||
def test_maps_admin | |||||
import = generate_import_with_mapping | |||||
first, second, third = new_records(User, 3) { import.run } | |||||
assert first.admin? | |||||
assert_not second.admin? | |||||
assert_not third.admin? | |||||
end | |||||
def test_maps_auth_information | |||||
import = generate_import_with_mapping | |||||
first, second, third = new_records(User, 3) { import.run } | |||||
# use password | |||||
assert User.try_to_login(first.login, 'password', false) | |||||
assert User.try_to_login(second.login, 'password', false) | |||||
# use auth_source | |||||
assert_nil first.auth_source | |||||
assert_nil second.auth_source | |||||
assert third.auth_source | |||||
assert_equal 'LDAP test server', third.auth_source.name | |||||
AuthSourceLdap.any_instance.expects(:authenticate).with(third.login, 'ldapassword').returns(true) | |||||
assert User.try_to_login(third.login, 'ldapassword', false) | |||||
end | |||||
def test_map_must_change_password | |||||
import = generate_import_with_mapping | |||||
first, second, third = new_records(User, 3) { import.run } | |||||
assert first.must_change_password? | |||||
assert_not second.must_change_password? | |||||
assert_not third.must_change_password? | |||||
end | |||||
def test_maps_status | |||||
import = generate_import_with_mapping | |||||
first, second, third = new_records(User, 3) { import.run } | |||||
assert first.active? | |||||
assert second.locked? | |||||
assert third.registered? | |||||
end | |||||
def test_maps_custom_fields | |||||
phone_number_cf = UserCustomField.find(4) | |||||
import = generate_import_with_mapping | |||||
import.mapping["cf_#{phone_number_cf.id}"] = '11' | |||||
import.save! | |||||
first, second, third = new_records(User, 3) { import.run } | |||||
assert_equal '000-1111-2222', first.custom_field_value(phone_number_cf) | |||||
assert_equal '333-4444-5555', second.custom_field_value(phone_number_cf) | |||||
assert_equal '666-7777-8888', third.custom_field_value(phone_number_cf) | |||||
end | |||||
protected | |||||
def generate_import(fixture_name='import_users.csv') | |||||
import = UserImport.new | |||||
import.user_id = 1 | |||||
import.file = uploaded_test_file(fixture_name, 'text/csv') | |||||
import.save! | |||||
import | |||||
end | |||||
def generate_import_with_mapping(fixture_name='import_users.csv') | |||||
import = generate_import(fixture_name) | |||||
import.settings = { | |||||
'separator' => ';', 'wrapper' => '"', 'encoding' => 'UTF-8', | |||||
'mapping' => { | |||||
'login' => '1', | |||||
'firstname' => '2', | |||||
'lastname' => '3', | |||||
'mail' => '4', | |||||
'language' => '5', | |||||
'admin' => '6', | |||||
'auth_source' => '7', | |||||
'password' => '8', | |||||
'must_change_passwd' => '9', | |||||
'status' => '10', | |||||
} | |||||
} | |||||
import.save! | |||||
import | |||||
end | |||||
end |