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.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/redmine_extensions/entity/entity_generator.rb +21 -24
  3. data/lib/generators/redmine_extensions/entity/templates/_form.html.erb.erb +4 -0
  4. data/lib/generators/redmine_extensions/entity/templates/_sidebar.html.erb.erb +1 -1
  5. data/lib/generators/redmine_extensions/entity/templates/context_menu.html.erb.erb +1 -1
  6. data/lib/generators/redmine_extensions/entity/templates/controller.rb.erb +19 -16
  7. data/lib/generators/redmine_extensions/entity/templates/custom_field.rb.erb +7 -7
  8. data/lib/generators/redmine_extensions/entity/templates/edit.js.erb.erb +10 -9
  9. data/lib/generators/redmine_extensions/entity/templates/en.yml.erb +1 -2
  10. data/lib/generators/redmine_extensions/entity/templates/index.api.rsb.erb +5 -5
  11. data/lib/generators/redmine_extensions/entity/templates/index.html.erb.erb +2 -0
  12. data/lib/generators/redmine_extensions/entity/templates/index.js.erb.erb +7 -6
  13. data/lib/generators/redmine_extensions/entity/templates/mail_added.html.erb.erb +1 -1
  14. data/lib/generators/redmine_extensions/entity/templates/mail_added.text.erb.erb +2 -2
  15. data/lib/generators/redmine_extensions/entity/templates/mail_updated.text.erb.erb +2 -2
  16. data/lib/generators/redmine_extensions/entity/templates/migration.rb.erb +3 -1
  17. data/lib/generators/redmine_extensions/entity/templates/model.rb.erb +4 -4
  18. data/lib/generators/redmine_extensions/entity/templates/new.js.erb.erb +10 -9
  19. data/lib/generators/redmine_extensions/entity/templates/query.rb.erb +8 -5
  20. data/lib/generators/redmine_extensions/entity/templates/routes.rb.erb +12 -12
  21. data/lib/generators/redmine_extensions/entity/templates/show.html.erb.erb +37 -37
  22. data/lib/generators/redmine_extensions/entity/templates/show.js.erb.erb +7 -6
  23. data/lib/generators/redmine_extensions/plugin/plugin_generator.rb +3 -1
  24. data/lib/generators/redmine_extensions/plugin/templates/after_init.rb.erb +22 -0
  25. data/lib/generators/redmine_extensions/plugin/templates/init.rb.erb +4 -22
  26. data/lib/generators/redmine_extensions/plugin/templates/javascript.js +1 -0
  27. data/lib/generators/redmine_extensions/plugin/templates/stylesheet.css +3 -0
  28. data/lib/redmine_extensions/version.rb +1 -1
  29. metadata +12 -216
  30. data/app/assets/javascripts/redmine_extensions/redmine_extensions.js.orig +0 -648
  31. data/app/views/easy_entity_assignments/_query_index.html.erb.orig +0 -16
  32. data/lib/redmine_extensions/redmine_patches/controllers/issues_controller_patch.rb +0 -9
  33. data/lib/redmine_extensions/version.rb.orig +0 -7
  34. data/spec/redmine/app/controllers/custom_field_enumerations_controller.rb +0 -75
  35. data/spec/redmine/app/controllers/imports_controller.rb +0 -121
  36. data/spec/redmine/app/helpers/imports_helper.rb +0 -47
  37. data/spec/redmine/app/models/custom_field_enumeration.rb +0 -90
  38. data/spec/redmine/app/models/import.rb +0 -249
  39. data/spec/redmine/app/models/import_item.rb +0 -22
  40. data/spec/redmine/app/models/issue_import.rb +0 -186
  41. data/spec/redmine/app/views/attachments/image.html.erb +0 -3
  42. data/spec/redmine/app/views/attachments/other.html.erb +0 -3
  43. data/spec/redmine/app/views/common/_image.html.erb +0 -1
  44. data/spec/redmine/app/views/common/_other.html.erb +0 -1
  45. data/spec/redmine/app/views/custom_field_enumerations/create.js.erb +0 -2
  46. data/spec/redmine/app/views/custom_field_enumerations/destroy.html.erb +0 -14
  47. data/spec/redmine/app/views/custom_field_enumerations/index.html.erb +0 -47
  48. data/spec/redmine/app/views/custom_fields/formats/_enumeration.erb +0 -12
  49. data/spec/redmine/app/views/imports/_fields_mapping.html.erb +0 -90
  50. data/spec/redmine/app/views/imports/mapping.html.erb +0 -52
  51. data/spec/redmine/app/views/imports/mapping.js.erb +0 -1
  52. data/spec/redmine/app/views/imports/new.html.erb +0 -15
  53. data/spec/redmine/app/views/imports/run.html.erb +0 -20
  54. data/spec/redmine/app/views/imports/run.js.erb +0 -11
  55. data/spec/redmine/app/views/imports/settings.html.erb +0 -30
  56. data/spec/redmine/app/views/imports/show.html.erb +0 -38
  57. data/spec/redmine/app/views/layouts/_file.html.erb +0 -15
  58. data/spec/redmine/app/views/mailer/security_notification.html.erb +0 -13
  59. data/spec/redmine/app/views/mailer/security_notification.text.erb +0 -8
  60. data/spec/redmine/app/views/mailer/settings_updated.html.erb +0 -14
  61. data/spec/redmine/app/views/mailer/settings_updated.text.erb +0 -12
  62. data/spec/redmine/app/views/queries/_query_form.html.erb +0 -62
  63. data/spec/redmine/app/views/repositories/_changeset.html.erb +0 -40
  64. data/spec/redmine/app/views/search/index.api.rsb +0 -12
  65. data/spec/redmine/app/views/settings/_api.html.erb +0 -10
  66. data/spec/redmine/app/views/settings/_attachments.html.erb +0 -21
  67. data/spec/redmine/app/views/wiki/_new_modal.html.erb +0 -21
  68. data/spec/redmine/app/views/wiki/new.html.erb +0 -17
  69. data/spec/redmine/app/views/wiki/new.js.erb +0 -2
  70. data/spec/redmine/appveyor.yml +0 -36
  71. data/spec/redmine/db/migrate/20150725112753_insert_allowed_statuses_for_new_issues.rb +0 -23
  72. data/spec/redmine/db/migrate/20150730122707_create_imports.rb +0 -13
  73. data/spec/redmine/db/migrate/20150730122735_create_import_items.rb +0 -10
  74. data/spec/redmine/db/migrate/20150921204850_change_time_entries_comments_limit_to_1024.rb +0 -9
  75. data/spec/redmine/db/migrate/20150921210243_change_wiki_contents_comments_limit_to_1024.rb +0 -11
  76. data/spec/redmine/db/migrate/20151020182334_change_attachments_filesize_limit_to_8.rb +0 -9
  77. data/spec/redmine/db/migrate/20151020182731_fix_comma_in_user_format_setting_value.rb +0 -13
  78. data/spec/redmine/db/migrate/20151021184614_change_issue_categories_name_limit_to_60.rb +0 -9
  79. data/spec/redmine/db/migrate/20151021185456_change_auth_sources_filter_to_text.rb +0 -9
  80. data/spec/redmine/db/migrate/20151021190616_change_user_preferences_hide_mail_default_to_true.rb +0 -9
  81. data/spec/redmine/db/migrate/20151024082034_add_tokens_updated_on.rb +0 -10
  82. data/spec/redmine/db/migrate/20151025072118_create_custom_field_enumerations.rb +0 -10
  83. data/spec/redmine/db/migrate/20151031095005_add_projects_default_version_id.rb +0 -12
  84. data/spec/redmine/db/migrate/20160404080304_force_password_reset_during_setup.rb +0 -9
  85. data/spec/redmine/db/migrate/20160416072926_remove_position_defaults.rb +0 -13
  86. data/spec/redmine/db/migrate/20160529063352_add_roles_settings.rb +0 -5
  87. data/spec/redmine/lib/redmine/acts/positioned.rb +0 -118
  88. data/spec/redmine/lib/redmine/helpers/url.rb +0 -35
  89. data/spec/redmine/lib/redmine/hook/listener.rb +0 -32
  90. data/spec/redmine/lib/redmine/hook/view_listener.rb +0 -78
  91. data/spec/redmine/log/test.log +0 -2
  92. data/spec/redmine/plugins/dummy_plugin/Gemfile +0 -1
  93. data/spec/redmine/plugins/dummy_plugin/app/controllers/dummy_autocompletes_controller.rb +0 -4
  94. data/spec/redmine/plugins/dummy_plugin/app/views/dummy_autocompletes/index.html.erb +0 -3
  95. data/spec/redmine/plugins/dummy_plugin/config/locales/en.yml +0 -2
  96. data/spec/redmine/plugins/dummy_plugin/config/routes.rb +0 -1
  97. data/spec/redmine/plugins/dummy_plugin/init.rb +0 -34
  98. data/spec/redmine/plugins/dummy_plugin/lib/dummy_plugin/easy_patch/redmine/controllers/issues_controller_patch.example +0 -30
  99. data/spec/redmine/plugins/dummy_plugin/lib/dummy_plugin/easy_patch/redmine/helpers/issues_helper_patch.example +0 -30
  100. data/spec/redmine/plugins/dummy_plugin/lib/dummy_plugin/easy_patch/redmine/models/issue_patch.example +0 -30
  101. data/spec/redmine/plugins/dummy_plugin/lib/dummy_plugin/hooks.rb +0 -5
  102. data/spec/redmine/plugins/dummy_plugin/lib/dummy_plugin/internals.rb +0 -4
  103. data/spec/redmine/public/images/jstoolbar/bt_precode.png +0 -0
  104. data/spec/redmine/public/images/reorder.png +0 -0
  105. data/spec/redmine/public/javascripts/jquery-1.11.1-ui-1.11.0-ujs-3.1.4.js +0 -21
  106. data/spec/redmine/public/javascripts/redmine_extensions/application.js +0 -13
  107. data/spec/redmine/public/javascripts/redmine_extensions/easy_togglers.js +0 -58
  108. data/spec/redmine/public/javascripts/redmine_extensions/jquery.entityarray.js +0 -130
  109. data/spec/redmine/public/javascripts/redmine_extensions/redmine_extensions.js +0 -642
  110. data/spec/redmine/public/javascripts/responsive.js +0 -83
  111. data/spec/redmine/public/stylesheets/responsive.css +0 -799
  112. data/spec/redmine/test/fixtures/files/import_dates.csv +0 -4
  113. data/spec/redmine/test/fixtures/files/import_iso8859-1.csv +0 -3
  114. data/spec/redmine/test/fixtures/files/import_issues.csv +0 -4
  115. data/spec/redmine/test/fixtures/ldap/slapd.centos6.conf +0 -24
  116. data/spec/redmine/test/fixtures/ldap/slapd.ubuntu.12.04.conf +0 -23
  117. data/spec/redmine/test/fixtures/mail_handler/issue_update_with_cc.eml +0 -19
  118. data/spec/redmine/test/fixtures/mail_handler/ticket_on_project_given_by_to_header.eml +0 -60
  119. data/spec/redmine/test/fixtures/mail_handler/ticket_with_text_attachment_iso-8859-2.eml +0 -31
  120. data/spec/redmine/test/functional/custom_field_enumerations_controller_test.rb +0 -115
  121. data/spec/redmine/test/functional/imports_controller_test.rb +0 -205
  122. data/spec/redmine/test/functional/sessions_controller_test.rb +0 -138
  123. data/spec/redmine/test/integration/api_test/search_test.rb +0 -92
  124. data/spec/redmine/test/integration/routing/imports_test.rb +0 -36
  125. data/spec/redmine/test/integration/sessions_test.rb +0 -97
  126. data/spec/redmine/test/ui/custom_fields_test_ui.rb +0 -38
  127. data/spec/redmine/test/unit/attachment_transaction_test.rb +0 -76
  128. data/spec/redmine/test/unit/helpers/journals_helper_test.rb +0 -48
  129. data/spec/redmine/test/unit/helpers/wiki_helper_test.rb +0 -45
  130. data/spec/redmine/test/unit/issue_import_test.rb +0 -178
  131. data/spec/redmine/test/unit/lib/redmine/acts/positioned_with_scope_test.rb +0 -53
  132. data/spec/redmine/test/unit/lib/redmine/acts/positioned_without_scope_test.rb +0 -55
  133. data/spec/redmine/test/unit/lib/redmine/field_format/enumeration_format_test.rb +0 -91
  134. 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,9 +0,0 @@
1
- module RedmineExtensions
2
- module IssuesControllerPatch
3
-
4
- def ahojky
5
- 'ahoj'
6
- end
7
-
8
- end
9
- end
@@ -1,7 +0,0 @@
1
- module RedmineExtensions
2
- <<<<<<< HEAD
3
- VERSION = '0.1.13'
4
- =======
5
- VERSION = '0.0.38'
6
- >>>>>>> stable
7
- 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)} --" : "&nbsp;".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