From 2d118da55c3ba674b541b478bdc6a54c7be714f9 Mon Sep 17 00:00:00 2001
From: Gregor Schmidt 
Date: Tue, 20 Feb 2018 15:54:37 +0100
Subject: [PATCH 1/3] Generalize issues imports
Extend import controller to support arbitrary imports based on Import
subclasses. This way, we may add other kinds of imports, by providing some views
and a custom import class. This may also be done from within plugins.
---
 app/controllers/imports_controller.rb              | 44 ++++++++++++++++++++--
 app/helpers/imports_helper.rb                      |  8 ++++
 app/models/import.rb                               | 12 ++++++
 app/models/issue_import.rb                         |  7 ++++
 ...ng.html.erb => _issues_fields_mapping.html.erb} |  2 +-
 app/views/imports/_issues_mapping.html.erb         | 16 ++++++++
 app/views/imports/_issues_mapping.js.erb           |  1 +
 app/views/imports/_issues_saved_objects.html.erb   |  7 ++++
 app/views/imports/_issues_sidebar.html.erb         |  3 ++
 app/views/imports/mapping.html.erb                 | 23 ++---------
 app/views/imports/mapping.js.erb                   |  2 +-
 app/views/imports/new.html.erb                     |  7 ++--
 app/views/imports/run.html.erb                     |  6 +--
 app/views/imports/settings.html.erb                |  6 +--
 app/views/imports/show.html.erb                    | 14 ++-----
 config/routes.rb                                   |  2 +-
 lib/redmine.rb                                     |  2 +-
 test/functional/imports_controller_test.rb         |  3 +-
 test/integration/routing/imports_test.rb           |  3 +-
 test/unit/issue_import_test.rb                     |  6 +++
 20 files changed, 121 insertions(+), 53 deletions(-)
 rename app/views/imports/{_fields_mapping.html.erb => _issues_fields_mapping.html.erb} (97%)
 create mode 100644 app/views/imports/_issues_mapping.html.erb
 create mode 100644 app/views/imports/_issues_mapping.js.erb
 create mode 100644 app/views/imports/_issues_saved_objects.html.erb
 create mode 100644 app/views/imports/_issues_sidebar.html.erb
diff --git a/app/controllers/imports_controller.rb b/app/controllers/imports_controller.rb
index 661eb7405..271b015cc 100644
--- a/app/controllers/imports_controller.rb
+++ b/app/controllers/imports_controller.rb
@@ -18,19 +18,20 @@
 require 'csv'
 
 class ImportsController < ApplicationController
-  menu_item :issues
-
   before_action :find_import, :only => [:show, :settings, :mapping, :run]
-  before_action :authorize_global
+  before_action :authorize_import
+
+  layout :import_layout
 
   helper :issues
   helper :queries
 
   def new
+    @import = import_type.new
   end
 
   def create
-    @import = IssueImport.new
+    @import = import_type.new
     @import.user = User.current
     @import.file = params[:file]
     @import.set_default_settings
@@ -94,6 +95,14 @@ class ImportsController < ApplicationController
     end
   end
 
+  def current_menu(project)
+    if import_layout == 'admin'
+      nil
+    else
+      :application_menu
+    end
+  end
+
   private
 
   def find_import
@@ -119,4 +128,31 @@ class ImportsController < ApplicationController
   def max_items_per_request
     5
   end
+
+  def import_layout
+    import_type && import_type.layout || 'base'
+  end
+
+  def menu_items
+    menu_item = import_type ? import_type.menu_item : nil
+
+    { self.controller_name.to_sym => { :actions => {}, :default => menu_item } }
+  end
+
+  def authorize_import
+    return render_404 unless import_type
+    return render_403 unless import_type.authorized?(User.current)
+  end
+
+  def import_type
+    return @import_type if defined? @import_type
+
+    @import_type =
+      if @import
+        @import.class
+      else
+        type = Object.const_get(params[:type]) rescue nil
+        type && type < Import ? type : nil
+      end
+  end
 end
diff --git a/app/helpers/imports_helper.rb b/app/helpers/imports_helper.rb
index 39f3b95ab..1a4836519 100644
--- a/app/helpers/imports_helper.rb
+++ b/app/helpers/imports_helper.rb
@@ -18,6 +18,14 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 module ImportsHelper
+  def import_title
+    l(:"label_import_#{import_partial_prefix}")
+  end
+
+  def import_partial_prefix
+    @import.class.name.sub('Import', '').underscore.pluralize
+  end
+
   def options_for_mapping_select(import, field, options={})
     tags = "".html_safe
     blank_text = options[:required] ? "-- #{l(:actionview_instancetag_blank_option)} --" : " ".html_safe
diff --git a/app/models/import.rb b/app/models/import.rb
index d2c53baac..194f46aa9 100644
--- a/app/models/import.rb
+++ b/app/models/import.rb
@@ -35,6 +35,18 @@ class Import < ActiveRecord::Base
     '%d-%m-%Y'
   ]
 
+  def self.menu_item
+    nil
+  end
+
+  def self.layout
+    'base'
+  end
+
+  def self.authorized?(user)
+    user.admin?
+  end
+
   def initialize(*args)
     super
     self.settings ||= {}
diff --git a/app/models/issue_import.rb b/app/models/issue_import.rb
index ad04c0be5..3e193ee3a 100644
--- a/app/models/issue_import.rb
+++ b/app/models/issue_import.rb
@@ -16,6 +16,13 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 class IssueImport < Import
+  def self.menu_item
+    :issues
+  end
+
+  def self.authorized?(user)
+    user.allowed_to?(:import_issues, nil, :global => true)
+  end
 
   # Returns the objects that were imported
   def saved_objects
diff --git a/app/views/imports/_fields_mapping.html.erb b/app/views/imports/_issues_fields_mapping.html.erb
similarity index 97%
rename from app/views/imports/_fields_mapping.html.erb
rename to app/views/imports/_issues_fields_mapping.html.erb
index f59350116..542a956ff 100644
--- a/app/views/imports/_fields_mapping.html.erb
+++ b/app/views/imports/_issues_fields_mapping.html.erb
@@ -54,7 +54,7 @@
 
 <% @custom_fields.each do |field| %>
   
-    
+    
     <%= mapping_select_tag @import, "cf_#{field.id}" %>
   
 <% end %>
diff --git a/app/views/imports/_issues_mapping.html.erb b/app/views/imports/_issues_mapping.html.erb
new file mode 100644
index 000000000..dc97d9c3a
--- /dev/null
+++ b/app/views/imports/_issues_mapping.html.erb
@@ -0,0 +1,16 @@
+
+
+<%= javascript_tag do %>
+  $('#fields-mapping').on('change', '#import_mapping_project_id, #import_mapping_tracker', function(){
+    $.ajax({
+      url: '<%= import_mapping_path(@import, :format => 'js') %>',
+      type: 'post',
+      data: $('#import-form').serialize()
+    });
+  });
+<% end %>
diff --git a/app/views/imports/_issues_mapping.js.erb b/app/views/imports/_issues_mapping.js.erb
new file mode 100644
index 000000000..012ccc537
--- /dev/null
+++ b/app/views/imports/_issues_mapping.js.erb
@@ -0,0 +1 @@
+$('#fields-mapping').html('<%= escape_javascript(render :partial => 'issues_fields_mapping') %>');
diff --git a/app/views/imports/_issues_saved_objects.html.erb b/app/views/imports/_issues_saved_objects.html.erb
new file mode 100644
index 000000000..f708a1c23
--- /dev/null
+++ b/app/views/imports/_issues_saved_objects.html.erb
@@ -0,0 +1,7 @@
+
+  <% saved_objects.each do |issue| %>
+    - <%= link_to_issue issue %>
 
+  <% end %>
+
+
+<%= link_to l(:label_issue_view_all), issues_path(:set_filter => 1, :status_id => '*', :issue_id => saved_objects.map(&:id).join(',')) %>
diff --git a/app/views/imports/_issues_sidebar.html.erb b/app/views/imports/_issues_sidebar.html.erb
new file mode 100644
index 000000000..e098175ec
--- /dev/null
+++ b/app/views/imports/_issues_sidebar.html.erb
@@ -0,0 +1,3 @@
+<% content_for :sidebar do %>
+  <%= render :partial => 'issues/sidebar' %>
+<% end %>
diff --git a/app/views/imports/mapping.html.erb b/app/views/imports/mapping.html.erb
index 2e225d6c2..1822f2802 100644
--- a/app/views/imports/mapping.html.erb
+++ b/app/views/imports/mapping.html.erb
@@ -1,12 +1,7 @@
-<%= l(:label_import_issues) %>
+<%= import_title %>
 
 <%= form_tag(import_mapping_path(@import), :id => "import-form") do %>
-  
+  <%= render :partial => "#{import_partial_prefix}_mapping" %>