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
end
end
+ def current_menu(project)
+ if import_layout == 'admin'
+ nil
+ else
+ :application_menu
+ end
+ end
+
private
def find_import
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
# 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
'%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 ||= {}
# 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
+++ /dev/null
-<p>
- <label for="import_mapping_project_id"><%= l(:label_project) %></label>
- <%= select_tag 'import_settings[mapping][project_id]',
- options_for_select(project_tree_options_for_select(@import.allowed_target_projects, :selected => @import.project)),
- :id => 'import_mapping_project_id' %>
-</p>
-<p>
- <label for="import_mapping_tracker"><%= l(:label_tracker) %></label>
- <%= mapping_select_tag @import, 'tracker', :required => true,
- :values => @import.allowed_target_trackers.sorted.map {|t| [t.name, t.id]} %>
-</p>
-<p>
- <label for="import_mapping_status"><%= l(:field_status) %></label>
- <%= mapping_select_tag @import, 'status' %>
-</p>
-
-<div class="splitcontent">
-<div class="splitcontentleft">
-<p>
- <label for="import_mapping_subject"><%= l(:field_subject) %></label>
- <%= mapping_select_tag @import, 'subject', :required => true %>
-</p>
-<p>
- <label for="import_mapping_description"><%= l(:field_description) %></label>
- <%= mapping_select_tag @import, 'description' %>
-</p>
-<p>
- <label for="import_mapping_priority"><%= l(:field_priority) %></label>
- <%= mapping_select_tag @import, 'priority' %>
-</p>
-<p>
- <label for="import_mapping_category"><%= l(:field_category) %></label>
- <%= mapping_select_tag @import, 'category' %>
- <% if User.current.allowed_to?(:manage_categories, @import.project) %>
- <label class="block">
- <%= check_box_tag 'import_settings[mapping][create_categories]', '1', @import.create_categories? %>
- <%= l(:label_create_missing_values) %>
- </label>
- <% end %>
-</p>
-<p>
- <label for="import_mapping_assigned_to"><%= l(:field_assigned_to) %></label>
- <%= mapping_select_tag @import, 'assigned_to' %>
-</p>
-<p>
- <label for="import_mapping_fixed_version"><%= l(:field_fixed_version) %></label>
- <%= mapping_select_tag @import, 'fixed_version' %>
- <% if User.current.allowed_to?(:manage_versions, @import.project) %>
- <label class="block">
- <%= check_box_tag 'import_settings[mapping][create_versions]', '1', @import.create_versions? %>
- <%= l(:label_create_missing_values) %>
- </label>
- <% end %>
-</p>
-<% @custom_fields.each do |field| %>
- <p>
- <label for="import_mapping_cf_<% field.id %>"><%= field.name %></label>
- <%= mapping_select_tag @import, "cf_#{field.id}" %>
- </p>
-<% end %>
-</div>
-
-<div class="splitcontentright">
-<p>
- <label for="import_mapping_is_private"><%= l(:field_is_private) %></label>
- <%= mapping_select_tag @import, 'is_private' %>
-</p>
-<p>
- <label for="import_mapping_parent_issue_id"><%= l(:field_parent_issue) %></label>
- <%= mapping_select_tag @import, 'parent_issue_id' %>
-</p>
-<p>
- <label for="import_mapping_start_date"><%= l(:field_start_date) %></label>
- <%= mapping_select_tag @import, 'start_date' %>
-</p>
-<p>
- <label for="import_mapping_due_date"><%= l(:field_due_date) %></label>
- <%= mapping_select_tag @import, 'due_date' %>
-</p>
-<p>
- <label for="import_mapping_estimated_hours"><%= l(:field_estimated_hours) %></label>
- <%= mapping_select_tag @import, 'estimated_hours' %>
-</p>
-<p>
- <label for="import_mapping_done_ratio"><%= l(:field_done_ratio) %></label>
- <%= mapping_select_tag @import, 'done_ratio' %>
-</p>
-</div>
-</div>
-
--- /dev/null
+<p>
+ <label for="import_mapping_project_id"><%= l(:label_project) %></label>
+ <%= select_tag 'import_settings[mapping][project_id]',
+ options_for_select(project_tree_options_for_select(@import.allowed_target_projects, :selected => @import.project)),
+ :id => 'import_mapping_project_id' %>
+</p>
+<p>
+ <label for="import_mapping_tracker"><%= l(:label_tracker) %></label>
+ <%= mapping_select_tag @import, 'tracker', :required => true,
+ :values => @import.allowed_target_trackers.sorted.map {|t| [t.name, t.id]} %>
+</p>
+<p>
+ <label for="import_mapping_status"><%= l(:field_status) %></label>
+ <%= mapping_select_tag @import, 'status' %>
+</p>
+
+<div class="splitcontent">
+<div class="splitcontentleft">
+<p>
+ <label for="import_mapping_subject"><%= l(:field_subject) %></label>
+ <%= mapping_select_tag @import, 'subject', :required => true %>
+</p>
+<p>
+ <label for="import_mapping_description"><%= l(:field_description) %></label>
+ <%= mapping_select_tag @import, 'description' %>
+</p>
+<p>
+ <label for="import_mapping_priority"><%= l(:field_priority) %></label>
+ <%= mapping_select_tag @import, 'priority' %>
+</p>
+<p>
+ <label for="import_mapping_category"><%= l(:field_category) %></label>
+ <%= mapping_select_tag @import, 'category' %>
+ <% if User.current.allowed_to?(:manage_categories, @import.project) %>
+ <label class="block">
+ <%= check_box_tag 'import_settings[mapping][create_categories]', '1', @import.create_categories? %>
+ <%= l(:label_create_missing_values) %>
+ </label>
+ <% end %>
+</p>
+<p>
+ <label for="import_mapping_assigned_to"><%= l(:field_assigned_to) %></label>
+ <%= mapping_select_tag @import, 'assigned_to' %>
+</p>
+<p>
+ <label for="import_mapping_fixed_version"><%= l(:field_fixed_version) %></label>
+ <%= mapping_select_tag @import, 'fixed_version' %>
+ <% if User.current.allowed_to?(:manage_versions, @import.project) %>
+ <label class="block">
+ <%= check_box_tag 'import_settings[mapping][create_versions]', '1', @import.create_versions? %>
+ <%= l(:label_create_missing_values) %>
+ </label>
+ <% end %>
+</p>
+<% @custom_fields.each do |field| %>
+ <p>
+ <label for="import_mapping_cf_<%= field.id %>"><%= field.name %></label>
+ <%= mapping_select_tag @import, "cf_#{field.id}" %>
+ </p>
+<% end %>
+</div>
+
+<div class="splitcontentright">
+<p>
+ <label for="import_mapping_is_private"><%= l(:field_is_private) %></label>
+ <%= mapping_select_tag @import, 'is_private' %>
+</p>
+<p>
+ <label for="import_mapping_parent_issue_id"><%= l(:field_parent_issue) %></label>
+ <%= mapping_select_tag @import, 'parent_issue_id' %>
+</p>
+<p>
+ <label for="import_mapping_start_date"><%= l(:field_start_date) %></label>
+ <%= mapping_select_tag @import, 'start_date' %>
+</p>
+<p>
+ <label for="import_mapping_due_date"><%= l(:field_due_date) %></label>
+ <%= mapping_select_tag @import, 'due_date' %>
+</p>
+<p>
+ <label for="import_mapping_estimated_hours"><%= l(:field_estimated_hours) %></label>
+ <%= mapping_select_tag @import, 'estimated_hours' %>
+</p>
+<p>
+ <label for="import_mapping_done_ratio"><%= l(:field_done_ratio) %></label>
+ <%= mapping_select_tag @import, 'done_ratio' %>
+</p>
+</div>
+</div>
+
--- /dev/null
+<fieldset class="box tabular">
+ <legend><%= l(:label_fields_mapping) %></legend>
+ <div id="fields-mapping">
+ <%= render :partial => 'issues_fields_mapping' %>
+ </div>
+</fieldset>
+
+<%= 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 %>
--- /dev/null
+$('#fields-mapping').html('<%= escape_javascript(render :partial => 'issues_fields_mapping') %>');
--- /dev/null
+<ul id="saved-items">
+ <% saved_objects.each do |issue| %>
+ <li><%= link_to_issue issue %></li>
+ <% end %>
+</ul>
+
+<p><%= link_to l(:label_issue_view_all), issues_path(:set_filter => 1, :status_id => '*', :issue_id => saved_objects.map(&:id).join(',')) %></p>
--- /dev/null
+<% content_for :sidebar do %>
+ <%= render :partial => 'issues/sidebar' %>
+<% end %>
-<h2><%= l(:label_import_issues) %></h2>
+<h2><%= import_title %></h2>
<%= form_tag(import_mapping_path(@import), :id => "import-form") do %>
- <fieldset class="box tabular">
- <legend><%= l(:label_fields_mapping) %></legend>
- <div id="fields-mapping">
- <%= render :partial => 'fields_mapping' %>
- </div>
- </fieldset>
+ <%= render :partial => "#{import_partial_prefix}_mapping" %>
<div class="autoscroll">
<fieldset class="box">
</p>
<% end %>
-<% content_for :sidebar do %>
- <%= render :partial => 'issues/sidebar' %>
-<% end %>
-
+<%= render :partial => "#{import_partial_prefix}_sidebar" %>
<%= javascript_tag do %>
$(document).ready(function() {
- $('#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()
- });
- });
-
$('#import-form').submit(function(){
$('#import-details').show().addClass('ajax-loading');
$('#import-progress').progressbar({value: 0, max: <%= @import.total_items || 0 %>});
});
-
});
<% end %>
-$('#fields-mapping').html('<%= escape_javascript(render :partial => 'fields_mapping') %>');
+<%= render :partial => "#{import_partial_prefix}_mapping" %>
-<h2><%= l(:label_import_issues) %></h2>
+<h2><%= import_title %></h2>
<%= form_tag(imports_path, :multipart => true) do %>
+ <%= hidden_field_tag 'type', @import.type %>
<fieldset class="box">
<legend><%= l(:label_select_file_to_import) %> (CSV)</legend>
<p>
<p><%= submit_tag l(:label_next).html_safe + " »".html_safe, :name => nil %></p>
<% end %>
-<% content_for :sidebar do %>
- <%= render :partial => 'issues/sidebar' %>
-<% end %>
+<%= render :partial => "#{import_partial_prefix}_sidebar" %>
-<h2><%= l(:label_import_issues) %></h2>
+<h2><%= import_title %></h2>
<div id="import-details">
<div id="import-progress"><div id="progress-label">0 / <%= @import.total_items.to_i %></div></div>
</div>
-<% content_for :sidebar do %>
- <%= render :partial => 'issues/sidebar' %>
-<% end %>
+<%= render :partial => "#{import_partial_prefix}_sidebar" %>
<%= javascript_tag do %>
$(document).ready(function() {
-<h2><%= l(:label_import_issues) %></h2>
+<h2><%= import_title %></h2>
<%= form_tag(import_settings_path(@import), :id => "import-form") do %>
<fieldset class="box tabular">
<p><%= submit_tag l(:label_next).html_safe + " »".html_safe, :name => nil %></p>
<% end %>
-<% content_for :sidebar do %>
- <%= render :partial => 'issues/sidebar' %>
-<% end %>
+<%= render :partial => "#{import_partial_prefix}_sidebar" %>
-<h2><%= l(:label_import_issues) %></h2>
+<h2><%= import_title %></h2>
<% if @import.saved_items.count > 0 %>
<p><%= l(:notice_import_finished, :count => @import.saved_items.count) %>:</p>
- <ul id="saved-items">
- <% @import.saved_objects.each do |issue| %>
- <li><%= link_to_issue issue %></li>
- <% end %>
- </ul>
-
- <p><%= link_to l(:label_issue_view_all), issues_path(:set_filter => 1, :status_id => '*', :issue_id => @import.saved_objects.map(&:id).join(',')) %></p>
+ <%= render :partial => "#{import_partial_prefix}_saved_objects", :locals => { saved_objects: @import.saved_objects } %>
<% end %>
<% if @import.unsaved_items.count > 0 %>
</table>
<% end %>
-<% content_for :sidebar do %>
- <%= render :partial => 'issues/sidebar' %>
-<% end %>
+<%= render :partial => "#{import_partial_prefix}_sidebar" %>
get 'projects/:id/issues/report', :to => 'reports#issue_report', :as => 'project_issues_report'
get 'projects/:id/issues/report/:detail', :to => 'reports#issue_report_details', :as => 'project_issues_report_details'
- get '/issues/imports/new', :to => 'imports#new', :as => 'new_issues_import'
+ get '/issues/imports/new', :to => 'imports#new', :defaults => { :type => 'IssueImport' }, :as => 'new_issues_import'
post '/imports', :to => 'imports#create', :as => 'imports'
get '/imports/:id', :to => 'imports#show', :as => 'import'
match '/imports/:id/settings', :to => 'imports#settings', :via => [:get, :post], :as => 'import_settings'
map.permission :view_issue_watchers, {}, :read => true
map.permission :add_issue_watchers, {:watchers => [:new, :create, :append, :autocomplete_for_user]}
map.permission :delete_issue_watchers, {:watchers => :destroy}
- map.permission :import_issues, {:imports => [:new, :create, :settings, :mapping, :run, :show]}
+ map.permission :import_issues, {}
# Issue categories
map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member
end
end
def test_new_should_display_the_upload_form
- get :new
+ get :new, :params => { :type => 'IssueImport' }
assert_response :success
assert_select 'input[name=?]', 'file'
end
def test_create_should_save_the_file
import = new_record(Import) do
post :create, :params => {
+ :type => 'IssueImport',
:file => uploaded_test_file('import_issues.csv', 'text/csv')
}
assert_response 302
class RoutingImportsTest < Redmine::RoutingTest
def test_imports
- should_route 'GET /issues/imports/new' => 'imports#new'
+ should_route 'GET /issues/imports/new' => 'imports#new', :type => 'IssueImport'
+
should_route 'POST /imports' => 'imports#create'
should_route 'GET /imports/4ae6bc' => 'imports#show', :id => '4ae6bc'
set_language_if_valid 'en'
end
+ def test_authorized
+ assert IssueImport.authorized?(User.find(1)) # admins
+ assert IssueImport.authorized?(User.find(2)) # has import_issues permission
+ assert !IssueImport.authorized?(User.find(3)) # does not have permission
+ end
+
def test_create_versions_should_create_missing_versions
import = generate_import_with_mapping
import.mapping.merge!('fixed_version' => '9', 'create_versions' => '1')