redmine_extensions 0.1.15 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/generators/redmine_extensions/entity/entity_generator.rb +21 -24
- data/lib/generators/redmine_extensions/entity/templates/_form.html.erb.erb +4 -0
- data/lib/generators/redmine_extensions/entity/templates/_sidebar.html.erb.erb +1 -1
- data/lib/generators/redmine_extensions/entity/templates/context_menu.html.erb.erb +1 -1
- data/lib/generators/redmine_extensions/entity/templates/controller.rb.erb +19 -16
- data/lib/generators/redmine_extensions/entity/templates/custom_field.rb.erb +7 -7
- data/lib/generators/redmine_extensions/entity/templates/edit.js.erb.erb +10 -9
- data/lib/generators/redmine_extensions/entity/templates/en.yml.erb +1 -2
- data/lib/generators/redmine_extensions/entity/templates/index.api.rsb.erb +5 -5
- data/lib/generators/redmine_extensions/entity/templates/index.html.erb.erb +2 -0
- data/lib/generators/redmine_extensions/entity/templates/index.js.erb.erb +7 -6
- data/lib/generators/redmine_extensions/entity/templates/mail_added.html.erb.erb +1 -1
- data/lib/generators/redmine_extensions/entity/templates/mail_added.text.erb.erb +2 -2
- data/lib/generators/redmine_extensions/entity/templates/mail_updated.text.erb.erb +2 -2
- data/lib/generators/redmine_extensions/entity/templates/migration.rb.erb +3 -1
- data/lib/generators/redmine_extensions/entity/templates/model.rb.erb +4 -4
- data/lib/generators/redmine_extensions/entity/templates/new.js.erb.erb +10 -9
- data/lib/generators/redmine_extensions/entity/templates/query.rb.erb +8 -5
- data/lib/generators/redmine_extensions/entity/templates/routes.rb.erb +12 -12
- data/lib/generators/redmine_extensions/entity/templates/show.html.erb.erb +37 -37
- data/lib/generators/redmine_extensions/entity/templates/show.js.erb.erb +7 -6
- data/lib/generators/redmine_extensions/plugin/plugin_generator.rb +3 -1
- data/lib/generators/redmine_extensions/plugin/templates/after_init.rb.erb +22 -0
- data/lib/generators/redmine_extensions/plugin/templates/init.rb.erb +4 -22
- data/lib/generators/redmine_extensions/plugin/templates/javascript.js +1 -0
- data/lib/generators/redmine_extensions/plugin/templates/stylesheet.css +3 -0
- data/lib/redmine_extensions/version.rb +1 -1
- metadata +12 -216
- data/app/assets/javascripts/redmine_extensions/redmine_extensions.js.orig +0 -648
- data/app/views/easy_entity_assignments/_query_index.html.erb.orig +0 -16
- data/lib/redmine_extensions/redmine_patches/controllers/issues_controller_patch.rb +0 -9
- data/lib/redmine_extensions/version.rb.orig +0 -7
- data/spec/redmine/app/controllers/custom_field_enumerations_controller.rb +0 -75
- data/spec/redmine/app/controllers/imports_controller.rb +0 -121
- data/spec/redmine/app/helpers/imports_helper.rb +0 -47
- data/spec/redmine/app/models/custom_field_enumeration.rb +0 -90
- data/spec/redmine/app/models/import.rb +0 -249
- data/spec/redmine/app/models/import_item.rb +0 -22
- data/spec/redmine/app/models/issue_import.rb +0 -186
- data/spec/redmine/app/views/attachments/image.html.erb +0 -3
- data/spec/redmine/app/views/attachments/other.html.erb +0 -3
- data/spec/redmine/app/views/common/_image.html.erb +0 -1
- data/spec/redmine/app/views/common/_other.html.erb +0 -1
- data/spec/redmine/app/views/custom_field_enumerations/create.js.erb +0 -2
- data/spec/redmine/app/views/custom_field_enumerations/destroy.html.erb +0 -14
- data/spec/redmine/app/views/custom_field_enumerations/index.html.erb +0 -47
- data/spec/redmine/app/views/custom_fields/formats/_enumeration.erb +0 -12
- data/spec/redmine/app/views/imports/_fields_mapping.html.erb +0 -90
- data/spec/redmine/app/views/imports/mapping.html.erb +0 -52
- data/spec/redmine/app/views/imports/mapping.js.erb +0 -1
- data/spec/redmine/app/views/imports/new.html.erb +0 -15
- data/spec/redmine/app/views/imports/run.html.erb +0 -20
- data/spec/redmine/app/views/imports/run.js.erb +0 -11
- data/spec/redmine/app/views/imports/settings.html.erb +0 -30
- data/spec/redmine/app/views/imports/show.html.erb +0 -38
- data/spec/redmine/app/views/layouts/_file.html.erb +0 -15
- data/spec/redmine/app/views/mailer/security_notification.html.erb +0 -13
- data/spec/redmine/app/views/mailer/security_notification.text.erb +0 -8
- data/spec/redmine/app/views/mailer/settings_updated.html.erb +0 -14
- data/spec/redmine/app/views/mailer/settings_updated.text.erb +0 -12
- data/spec/redmine/app/views/queries/_query_form.html.erb +0 -62
- data/spec/redmine/app/views/repositories/_changeset.html.erb +0 -40
- data/spec/redmine/app/views/search/index.api.rsb +0 -12
- data/spec/redmine/app/views/settings/_api.html.erb +0 -10
- data/spec/redmine/app/views/settings/_attachments.html.erb +0 -21
- data/spec/redmine/app/views/wiki/_new_modal.html.erb +0 -21
- data/spec/redmine/app/views/wiki/new.html.erb +0 -17
- data/spec/redmine/app/views/wiki/new.js.erb +0 -2
- data/spec/redmine/appveyor.yml +0 -36
- data/spec/redmine/db/migrate/20150725112753_insert_allowed_statuses_for_new_issues.rb +0 -23
- data/spec/redmine/db/migrate/20150730122707_create_imports.rb +0 -13
- data/spec/redmine/db/migrate/20150730122735_create_import_items.rb +0 -10
- data/spec/redmine/db/migrate/20150921204850_change_time_entries_comments_limit_to_1024.rb +0 -9
- data/spec/redmine/db/migrate/20150921210243_change_wiki_contents_comments_limit_to_1024.rb +0 -11
- data/spec/redmine/db/migrate/20151020182334_change_attachments_filesize_limit_to_8.rb +0 -9
- data/spec/redmine/db/migrate/20151020182731_fix_comma_in_user_format_setting_value.rb +0 -13
- data/spec/redmine/db/migrate/20151021184614_change_issue_categories_name_limit_to_60.rb +0 -9
- data/spec/redmine/db/migrate/20151021185456_change_auth_sources_filter_to_text.rb +0 -9
- data/spec/redmine/db/migrate/20151021190616_change_user_preferences_hide_mail_default_to_true.rb +0 -9
- data/spec/redmine/db/migrate/20151024082034_add_tokens_updated_on.rb +0 -10
- data/spec/redmine/db/migrate/20151025072118_create_custom_field_enumerations.rb +0 -10
- data/spec/redmine/db/migrate/20151031095005_add_projects_default_version_id.rb +0 -12
- data/spec/redmine/db/migrate/20160404080304_force_password_reset_during_setup.rb +0 -9
- data/spec/redmine/db/migrate/20160416072926_remove_position_defaults.rb +0 -13
- data/spec/redmine/db/migrate/20160529063352_add_roles_settings.rb +0 -5
- data/spec/redmine/lib/redmine/acts/positioned.rb +0 -118
- data/spec/redmine/lib/redmine/helpers/url.rb +0 -35
- data/spec/redmine/lib/redmine/hook/listener.rb +0 -32
- data/spec/redmine/lib/redmine/hook/view_listener.rb +0 -78
- data/spec/redmine/log/test.log +0 -2
- data/spec/redmine/plugins/dummy_plugin/Gemfile +0 -1
- data/spec/redmine/plugins/dummy_plugin/app/controllers/dummy_autocompletes_controller.rb +0 -4
- data/spec/redmine/plugins/dummy_plugin/app/views/dummy_autocompletes/index.html.erb +0 -3
- data/spec/redmine/plugins/dummy_plugin/config/locales/en.yml +0 -2
- data/spec/redmine/plugins/dummy_plugin/config/routes.rb +0 -1
- data/spec/redmine/plugins/dummy_plugin/init.rb +0 -34
- data/spec/redmine/plugins/dummy_plugin/lib/dummy_plugin/easy_patch/redmine/controllers/issues_controller_patch.example +0 -30
- data/spec/redmine/plugins/dummy_plugin/lib/dummy_plugin/easy_patch/redmine/helpers/issues_helper_patch.example +0 -30
- data/spec/redmine/plugins/dummy_plugin/lib/dummy_plugin/easy_patch/redmine/models/issue_patch.example +0 -30
- data/spec/redmine/plugins/dummy_plugin/lib/dummy_plugin/hooks.rb +0 -5
- data/spec/redmine/plugins/dummy_plugin/lib/dummy_plugin/internals.rb +0 -4
- data/spec/redmine/public/images/jstoolbar/bt_precode.png +0 -0
- data/spec/redmine/public/images/reorder.png +0 -0
- data/spec/redmine/public/javascripts/jquery-1.11.1-ui-1.11.0-ujs-3.1.4.js +0 -21
- data/spec/redmine/public/javascripts/redmine_extensions/application.js +0 -13
- data/spec/redmine/public/javascripts/redmine_extensions/easy_togglers.js +0 -58
- data/spec/redmine/public/javascripts/redmine_extensions/jquery.entityarray.js +0 -130
- data/spec/redmine/public/javascripts/redmine_extensions/redmine_extensions.js +0 -642
- data/spec/redmine/public/javascripts/responsive.js +0 -83
- data/spec/redmine/public/stylesheets/responsive.css +0 -799
- data/spec/redmine/test/fixtures/files/import_dates.csv +0 -4
- data/spec/redmine/test/fixtures/files/import_iso8859-1.csv +0 -3
- data/spec/redmine/test/fixtures/files/import_issues.csv +0 -4
- data/spec/redmine/test/fixtures/ldap/slapd.centos6.conf +0 -24
- data/spec/redmine/test/fixtures/ldap/slapd.ubuntu.12.04.conf +0 -23
- data/spec/redmine/test/fixtures/mail_handler/issue_update_with_cc.eml +0 -19
- data/spec/redmine/test/fixtures/mail_handler/ticket_on_project_given_by_to_header.eml +0 -60
- data/spec/redmine/test/fixtures/mail_handler/ticket_with_text_attachment_iso-8859-2.eml +0 -31
- data/spec/redmine/test/functional/custom_field_enumerations_controller_test.rb +0 -115
- data/spec/redmine/test/functional/imports_controller_test.rb +0 -205
- data/spec/redmine/test/functional/sessions_controller_test.rb +0 -138
- data/spec/redmine/test/integration/api_test/search_test.rb +0 -92
- data/spec/redmine/test/integration/routing/imports_test.rb +0 -36
- data/spec/redmine/test/integration/sessions_test.rb +0 -97
- data/spec/redmine/test/ui/custom_fields_test_ui.rb +0 -38
- data/spec/redmine/test/unit/attachment_transaction_test.rb +0 -76
- data/spec/redmine/test/unit/helpers/journals_helper_test.rb +0 -48
- data/spec/redmine/test/unit/helpers/wiki_helper_test.rb +0 -45
- data/spec/redmine/test/unit/issue_import_test.rb +0 -178
- data/spec/redmine/test/unit/lib/redmine/acts/positioned_with_scope_test.rb +0 -53
- data/spec/redmine/test/unit/lib/redmine/acts/positioned_without_scope_test.rb +0 -55
- data/spec/redmine/test/unit/lib/redmine/field_format/enumeration_format_test.rb +0 -91
- data/spec/support/easy_queries_helpers.rb +0 -0
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<<<<<<< HEAD
|
|
2
|
-
<% query_outputs(query, entities: referenced_entities, options: { hascontextmenu: true, disable_sort: true }).each do |output| %>
|
|
3
|
-
<%= output.render_data %>
|
|
4
|
-
=======
|
|
5
|
-
<% if display_style == :list %>
|
|
6
|
-
<%= render :partial => 'easy_queries/easy_query_entities_list', :locals => {:query => query, :entities => entities, :options => {:hascontextmenu => true, :disable_sort => true} } -%>
|
|
7
|
-
<% elsif display_style == :tile %>
|
|
8
|
-
<div class="easy-entity-cards-container">
|
|
9
|
-
<div class="splitcontent">
|
|
10
|
-
<% entities.each do |referenced_entity| %>
|
|
11
|
-
<%# render_easy_entity_card(referenced_entity, entity, options.merge(:referenced_entities => referenced_entities)) %>
|
|
12
|
-
<% end %>
|
|
13
|
-
</div>
|
|
14
|
-
</div>
|
|
15
|
-
>>>>>>> stable
|
|
16
|
-
<% end %>
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# Redmine - project management software
|
|
2
|
-
# Copyright (C) 2006-2016 Jean-Philippe Lang
|
|
3
|
-
#
|
|
4
|
-
# This program is free software; you can redistribute it and/or
|
|
5
|
-
# modify it under the terms of the GNU General Public License
|
|
6
|
-
# as published by the Free Software Foundation; either version 2
|
|
7
|
-
# of the License, or (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# You should have received a copy of the GNU General Public License
|
|
15
|
-
# along with this program; if not, write to the Free Software
|
|
16
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
17
|
-
|
|
18
|
-
class CustomFieldEnumerationsController < ApplicationController
|
|
19
|
-
layout 'admin'
|
|
20
|
-
|
|
21
|
-
before_action :require_admin
|
|
22
|
-
before_action :find_custom_field
|
|
23
|
-
before_action :find_enumeration, :only => :destroy
|
|
24
|
-
|
|
25
|
-
helper :custom_fields
|
|
26
|
-
|
|
27
|
-
def index
|
|
28
|
-
@values = @custom_field.enumerations.order(:position)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def create
|
|
32
|
-
@value = @custom_field.enumerations.build
|
|
33
|
-
@value.safe_attributes = params[:custom_field_enumeration]
|
|
34
|
-
@value.save
|
|
35
|
-
respond_to do |format|
|
|
36
|
-
format.html { redirect_to custom_field_enumerations_path(@custom_field) }
|
|
37
|
-
format.js
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def update_each
|
|
42
|
-
saved = CustomFieldEnumeration.update_each(@custom_field, params[:custom_field_enumerations]) do |enumeration, enumeration_attributes|
|
|
43
|
-
enumeration.safe_attributes = enumeration_attributes
|
|
44
|
-
end
|
|
45
|
-
if saved
|
|
46
|
-
flash[:notice] = l(:notice_successful_update)
|
|
47
|
-
end
|
|
48
|
-
redirect_to :action => 'index'
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def destroy
|
|
52
|
-
reassign_to = @custom_field.enumerations.find_by_id(params[:reassign_to_id])
|
|
53
|
-
if reassign_to.nil? && @value.in_use?
|
|
54
|
-
@enumerations = @custom_field.enumerations - [@value]
|
|
55
|
-
render :action => 'destroy'
|
|
56
|
-
return
|
|
57
|
-
end
|
|
58
|
-
@value.destroy(reassign_to)
|
|
59
|
-
redirect_to custom_field_enumerations_path(@custom_field)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
private
|
|
63
|
-
|
|
64
|
-
def find_custom_field
|
|
65
|
-
@custom_field = CustomField.find(params[:custom_field_id])
|
|
66
|
-
rescue ActiveRecord::RecordNotFound
|
|
67
|
-
render_404
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def find_enumeration
|
|
71
|
-
@value = @custom_field.enumerations.find(params[:id])
|
|
72
|
-
rescue ActiveRecord::RecordNotFound
|
|
73
|
-
render_404
|
|
74
|
-
end
|
|
75
|
-
end
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
# Redmine - project management software
|
|
2
|
-
# Copyright (C) 2006-2016 Jean-Philippe Lang
|
|
3
|
-
#
|
|
4
|
-
# This program is free software; you can redistribute it and/or
|
|
5
|
-
# modify it under the terms of the GNU General Public License
|
|
6
|
-
# as published by the Free Software Foundation; either version 2
|
|
7
|
-
# of the License, or (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# You should have received a copy of the GNU General Public License
|
|
15
|
-
# along with this program; if not, write to the Free Software
|
|
16
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
17
|
-
|
|
18
|
-
require 'csv'
|
|
19
|
-
|
|
20
|
-
class ImportsController < ApplicationController
|
|
21
|
-
|
|
22
|
-
before_action :find_import, :only => [:show, :settings, :mapping, :run]
|
|
23
|
-
before_action :authorize_global
|
|
24
|
-
|
|
25
|
-
helper :issues
|
|
26
|
-
helper :queries
|
|
27
|
-
|
|
28
|
-
def new
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def create
|
|
32
|
-
@import = IssueImport.new
|
|
33
|
-
@import.user = User.current
|
|
34
|
-
@import.file = params[:file]
|
|
35
|
-
@import.set_default_settings
|
|
36
|
-
|
|
37
|
-
if @import.save
|
|
38
|
-
redirect_to import_settings_path(@import)
|
|
39
|
-
else
|
|
40
|
-
render :action => 'new'
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def show
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def settings
|
|
48
|
-
if request.post? && @import.parse_file
|
|
49
|
-
redirect_to import_mapping_path(@import)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
rescue CSV::MalformedCSVError => e
|
|
53
|
-
flash.now[:error] = l(:error_invalid_csv_file_or_settings)
|
|
54
|
-
rescue ArgumentError, Encoding::InvalidByteSequenceError => e
|
|
55
|
-
flash.now[:error] = l(:error_invalid_file_encoding, :encoding => ERB::Util.h(@import.settings['encoding']))
|
|
56
|
-
rescue SystemCallError => e
|
|
57
|
-
flash.now[:error] = l(:error_can_not_read_import_file)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def mapping
|
|
61
|
-
@custom_fields = @import.mappable_custom_fields
|
|
62
|
-
|
|
63
|
-
if request.post?
|
|
64
|
-
respond_to do |format|
|
|
65
|
-
format.html {
|
|
66
|
-
if params[:previous]
|
|
67
|
-
redirect_to import_settings_path(@import)
|
|
68
|
-
else
|
|
69
|
-
redirect_to import_run_path(@import)
|
|
70
|
-
end
|
|
71
|
-
}
|
|
72
|
-
format.js # updates mapping form on project or tracker change
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def run
|
|
78
|
-
if request.post?
|
|
79
|
-
@current = @import.run(
|
|
80
|
-
:max_items => max_items_per_request,
|
|
81
|
-
:max_time => 10.seconds
|
|
82
|
-
)
|
|
83
|
-
respond_to do |format|
|
|
84
|
-
format.html {
|
|
85
|
-
if @import.finished?
|
|
86
|
-
redirect_to import_path(@import)
|
|
87
|
-
else
|
|
88
|
-
redirect_to import_run_path(@import)
|
|
89
|
-
end
|
|
90
|
-
}
|
|
91
|
-
format.js
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
private
|
|
97
|
-
|
|
98
|
-
def find_import
|
|
99
|
-
@import = Import.where(:user_id => User.current.id, :filename => params[:id]).first
|
|
100
|
-
if @import.nil?
|
|
101
|
-
render_404
|
|
102
|
-
return
|
|
103
|
-
elsif @import.finished? && action_name != 'show'
|
|
104
|
-
redirect_to import_path(@import)
|
|
105
|
-
return
|
|
106
|
-
end
|
|
107
|
-
update_from_params if request.post?
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def update_from_params
|
|
111
|
-
if params[:import_settings].is_a?(Hash)
|
|
112
|
-
@import.settings ||= {}
|
|
113
|
-
@import.settings.merge!(params[:import_settings])
|
|
114
|
-
@import.save!
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def max_items_per_request
|
|
119
|
-
5
|
|
120
|
-
end
|
|
121
|
-
end
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
#
|
|
3
|
-
# Redmine - project management software
|
|
4
|
-
# Copyright (C) 2006-2016 Jean-Philippe Lang
|
|
5
|
-
#
|
|
6
|
-
# This program is free software; you can redistribute it and/or
|
|
7
|
-
# modify it under the terms of the GNU General Public License
|
|
8
|
-
# as published by the Free Software Foundation; either version 2
|
|
9
|
-
# of the License, or (at your option) any later version.
|
|
10
|
-
#
|
|
11
|
-
# This program is distributed in the hope that it will be useful,
|
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
-
# GNU General Public License for more details.
|
|
15
|
-
#
|
|
16
|
-
# You should have received a copy of the GNU General Public License
|
|
17
|
-
# along with this program; if not, write to the Free Software
|
|
18
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
19
|
-
|
|
20
|
-
module ImportsHelper
|
|
21
|
-
def options_for_mapping_select(import, field, options={})
|
|
22
|
-
tags = "".html_safe
|
|
23
|
-
blank_text = options[:required] ? "-- #{l(:actionview_instancetag_blank_option)} --" : " ".html_safe
|
|
24
|
-
tags << content_tag('option', blank_text, :value => '')
|
|
25
|
-
tags << options_for_select(import.columns_options, import.mapping[field])
|
|
26
|
-
if values = options[:values]
|
|
27
|
-
tags << content_tag('option', '--', :disabled => true)
|
|
28
|
-
tags << options_for_select(values.map {|text, value| [text, "value:#{value}"]}, import.mapping[field])
|
|
29
|
-
end
|
|
30
|
-
tags
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def mapping_select_tag(import, field, options={})
|
|
34
|
-
name = "import_settings[mapping][#{field}]"
|
|
35
|
-
select_tag name, options_for_mapping_select(import, field, options), :id => "import_mapping_#{field}"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Returns the options for the date_format setting
|
|
39
|
-
def date_format_options
|
|
40
|
-
Import::DATE_FORMATS.map do |f|
|
|
41
|
-
format = f.gsub('%', '').gsub(/[dmY]/) do
|
|
42
|
-
{'d' => 'DD', 'm' => 'MM', 'Y' => 'YYYY'}[$&]
|
|
43
|
-
end
|
|
44
|
-
[format, f]
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# Redmine - project management software
|
|
2
|
-
# Copyright (C) 2006-2016 Jean-Philippe Lang
|
|
3
|
-
#
|
|
4
|
-
# This program is free software; you can redistribute it and/or
|
|
5
|
-
# modify it under the terms of the GNU General Public License
|
|
6
|
-
# as published by the Free Software Foundation; either version 2
|
|
7
|
-
# of the License, or (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# You should have received a copy of the GNU General Public License
|
|
15
|
-
# along with this program; if not, write to the Free Software
|
|
16
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
17
|
-
|
|
18
|
-
class CustomFieldEnumeration < ActiveRecord::Base
|
|
19
|
-
include Redmine::SafeAttributes
|
|
20
|
-
|
|
21
|
-
belongs_to :custom_field
|
|
22
|
-
attr_accessible :name, :active, :position
|
|
23
|
-
|
|
24
|
-
validates_presence_of :name, :position, :custom_field_id
|
|
25
|
-
validates_length_of :name, :maximum => 60
|
|
26
|
-
validates_numericality_of :position, :only_integer => true
|
|
27
|
-
before_create :set_position
|
|
28
|
-
|
|
29
|
-
scope :active, lambda { where(:active => true) }
|
|
30
|
-
|
|
31
|
-
safe_attributes 'name',
|
|
32
|
-
'active',
|
|
33
|
-
'position'
|
|
34
|
-
|
|
35
|
-
def to_s
|
|
36
|
-
name.to_s
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def objects_count
|
|
40
|
-
custom_values.count
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def in_use?
|
|
44
|
-
objects_count > 0
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
alias :destroy_without_reassign :destroy
|
|
48
|
-
def destroy(reassign_to=nil)
|
|
49
|
-
if reassign_to
|
|
50
|
-
custom_values.update_all(:value => reassign_to.id.to_s)
|
|
51
|
-
end
|
|
52
|
-
destroy_without_reassign
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def custom_values
|
|
56
|
-
custom_field.custom_values.where(:value => id.to_s)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def self.update_each(custom_field, attributes)
|
|
60
|
-
return unless attributes.is_a?(Hash)
|
|
61
|
-
transaction do
|
|
62
|
-
attributes.each do |enumeration_id, enumeration_attributes|
|
|
63
|
-
enumeration = custom_field.enumerations.find_by_id(enumeration_id)
|
|
64
|
-
if enumeration
|
|
65
|
-
if block_given?
|
|
66
|
-
yield enumeration, enumeration_attributes
|
|
67
|
-
else
|
|
68
|
-
enumeration.attributes = enumeration_attributes
|
|
69
|
-
end
|
|
70
|
-
unless enumeration.save
|
|
71
|
-
raise ActiveRecord::Rollback
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def self.fields_for_order_statement(table=nil)
|
|
79
|
-
table ||= table_name
|
|
80
|
-
columns = ['position']
|
|
81
|
-
columns.uniq.map {|field| "#{table}.#{field}"}
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
private
|
|
85
|
-
|
|
86
|
-
def set_position
|
|
87
|
-
max = self.class.where(:custom_field_id => custom_field_id).maximum(:position) || 0
|
|
88
|
-
self.position = max + 1
|
|
89
|
-
end
|
|
90
|
-
end
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
# Redmine - project management software
|
|
2
|
-
# Copyright (C) 2006-2016 Jean-Philippe Lang
|
|
3
|
-
#
|
|
4
|
-
# This program is free software; you can redistribute it and/or
|
|
5
|
-
# modify it under the terms of the GNU General Public License
|
|
6
|
-
# as published by the Free Software Foundation; either version 2
|
|
7
|
-
# of the License, or (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# You should have received a copy of the GNU General Public License
|
|
15
|
-
# along with this program; if not, write to the Free Software
|
|
16
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
17
|
-
|
|
18
|
-
require 'csv'
|
|
19
|
-
|
|
20
|
-
class Import < ActiveRecord::Base
|
|
21
|
-
has_many :items, :class_name => 'ImportItem', :dependent => :delete_all
|
|
22
|
-
belongs_to :user
|
|
23
|
-
serialize :settings
|
|
24
|
-
|
|
25
|
-
before_destroy :remove_file
|
|
26
|
-
|
|
27
|
-
validates_presence_of :filename, :user_id
|
|
28
|
-
validates_length_of :filename, :maximum => 255
|
|
29
|
-
|
|
30
|
-
DATE_FORMATS = [
|
|
31
|
-
'%Y-%m-%d',
|
|
32
|
-
'%d/%m/%Y',
|
|
33
|
-
'%m/%d/%Y',
|
|
34
|
-
'%d.%m.%Y',
|
|
35
|
-
'%d-%m-%Y'
|
|
36
|
-
]
|
|
37
|
-
|
|
38
|
-
def initialize(*args)
|
|
39
|
-
super
|
|
40
|
-
self.settings ||= {}
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def file=(arg)
|
|
44
|
-
return unless arg.present? && arg.size > 0
|
|
45
|
-
|
|
46
|
-
self.filename = generate_filename
|
|
47
|
-
Redmine::Utils.save_upload(arg, filepath)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def set_default_settings
|
|
51
|
-
separator = lu(user, :general_csv_separator)
|
|
52
|
-
if file_exists?
|
|
53
|
-
begin
|
|
54
|
-
content = File.read(filepath, 256)
|
|
55
|
-
separator = [',', ';'].sort_by {|sep| content.count(sep) }.last
|
|
56
|
-
rescue Exception => e
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
wrapper = '"'
|
|
60
|
-
encoding = lu(user, :general_csv_encoding)
|
|
61
|
-
|
|
62
|
-
date_format = lu(user, "date.formats.default", :default => "foo")
|
|
63
|
-
date_format = DATE_FORMATS.first unless DATE_FORMATS.include?(date_format)
|
|
64
|
-
|
|
65
|
-
self.settings.merge!(
|
|
66
|
-
'separator' => separator,
|
|
67
|
-
'wrapper' => wrapper,
|
|
68
|
-
'encoding' => encoding,
|
|
69
|
-
'date_format' => date_format
|
|
70
|
-
)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def to_param
|
|
74
|
-
filename
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Returns the full path of the file to import
|
|
78
|
-
# It is stored in tmp/imports with a random hex as filename
|
|
79
|
-
def filepath
|
|
80
|
-
if filename.present? && filename =~ /\A[0-9a-f]+\z/
|
|
81
|
-
File.join(Rails.root, "tmp", "imports", filename)
|
|
82
|
-
else
|
|
83
|
-
nil
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# Returns true if the file to import exists
|
|
88
|
-
def file_exists?
|
|
89
|
-
filepath.present? && File.exists?(filepath)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Returns the headers as an array that
|
|
93
|
-
# can be used for select options
|
|
94
|
-
def columns_options(default=nil)
|
|
95
|
-
i = -1
|
|
96
|
-
headers.map {|h| [h, i+=1]}
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# Parses the file to import and updates the total number of items
|
|
100
|
-
def parse_file
|
|
101
|
-
count = 0
|
|
102
|
-
read_items {|row, i| count=i}
|
|
103
|
-
update_attribute :total_items, count
|
|
104
|
-
count
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# Reads the items to import and yields the given block for each item
|
|
108
|
-
def read_items
|
|
109
|
-
i = 0
|
|
110
|
-
headers = true
|
|
111
|
-
read_rows do |row|
|
|
112
|
-
if i == 0 && headers
|
|
113
|
-
headers = false
|
|
114
|
-
next
|
|
115
|
-
end
|
|
116
|
-
i+= 1
|
|
117
|
-
yield row, i if block_given?
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
# Returns the count first rows of the file (including headers)
|
|
122
|
-
def first_rows(count=4)
|
|
123
|
-
rows = []
|
|
124
|
-
read_rows do |row|
|
|
125
|
-
rows << row
|
|
126
|
-
break if rows.size >= count
|
|
127
|
-
end
|
|
128
|
-
rows
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
# Returns an array of headers
|
|
132
|
-
def headers
|
|
133
|
-
first_rows(1).first || []
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Returns the mapping options
|
|
137
|
-
def mapping
|
|
138
|
-
settings['mapping'] || {}
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# Imports items and returns the position of the last processed item
|
|
142
|
-
def run(options={})
|
|
143
|
-
max_items = options[:max_items]
|
|
144
|
-
max_time = options[:max_time]
|
|
145
|
-
current = 0
|
|
146
|
-
imported = 0
|
|
147
|
-
resume_after = items.maximum(:position) || 0
|
|
148
|
-
interrupted = false
|
|
149
|
-
started_on = Time.now
|
|
150
|
-
|
|
151
|
-
read_items do |row, position|
|
|
152
|
-
if (max_items && imported >= max_items) || (max_time && Time.now >= started_on + max_time)
|
|
153
|
-
interrupted = true
|
|
154
|
-
break
|
|
155
|
-
end
|
|
156
|
-
if position > resume_after
|
|
157
|
-
item = items.build
|
|
158
|
-
item.position = position
|
|
159
|
-
|
|
160
|
-
if object = build_object(row)
|
|
161
|
-
if object.save
|
|
162
|
-
item.obj_id = object.id
|
|
163
|
-
else
|
|
164
|
-
item.message = object.errors.full_messages.join("\n")
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
item.save!
|
|
169
|
-
imported += 1
|
|
170
|
-
end
|
|
171
|
-
current = position
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
if imported == 0 || interrupted == false
|
|
175
|
-
if total_items.nil?
|
|
176
|
-
update_attribute :total_items, current
|
|
177
|
-
end
|
|
178
|
-
update_attribute :finished, true
|
|
179
|
-
remove_file
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
current
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def unsaved_items
|
|
186
|
-
items.where(:obj_id => nil)
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def saved_items
|
|
190
|
-
items.where("obj_id IS NOT NULL")
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
private
|
|
194
|
-
|
|
195
|
-
def read_rows
|
|
196
|
-
return unless file_exists?
|
|
197
|
-
|
|
198
|
-
csv_options = {:headers => false}
|
|
199
|
-
csv_options[:encoding] = settings['encoding'].to_s.presence || 'UTF-8'
|
|
200
|
-
separator = settings['separator'].to_s
|
|
201
|
-
csv_options[:col_sep] = separator if separator.size == 1
|
|
202
|
-
wrapper = settings['wrapper'].to_s
|
|
203
|
-
csv_options[:quote_char] = wrapper if wrapper.size == 1
|
|
204
|
-
|
|
205
|
-
CSV.foreach(filepath, csv_options) do |row|
|
|
206
|
-
yield row if block_given?
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def row_value(row, key)
|
|
211
|
-
if index = mapping[key].presence
|
|
212
|
-
row[index.to_i].presence
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
def row_date(row, key)
|
|
217
|
-
if s = row_value(row, key)
|
|
218
|
-
format = settings['date_format']
|
|
219
|
-
format = DATE_FORMATS.first unless DATE_FORMATS.include?(format)
|
|
220
|
-
Date.strptime(s, format) rescue s
|
|
221
|
-
end
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
# Builds a record for the given row and returns it
|
|
225
|
-
# To be implemented by subclasses
|
|
226
|
-
def build_object(row)
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
# Generates a filename used to store the import file
|
|
230
|
-
def generate_filename
|
|
231
|
-
Redmine::Utils.random_hex(16)
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
# Deletes the import file
|
|
235
|
-
def remove_file
|
|
236
|
-
if file_exists?
|
|
237
|
-
begin
|
|
238
|
-
File.delete filepath
|
|
239
|
-
rescue Exception => e
|
|
240
|
-
logger.error "Unable to delete file #{filepath}: #{e.message}" if logger
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
# Returns true if value is a string that represents a true value
|
|
246
|
-
def yes?(value)
|
|
247
|
-
value == lu(user, :general_text_yes) || value == '1'
|
|
248
|
-
end
|
|
249
|
-
end
|