mirror of
https://github.com/meineerde/redmine.git
synced 2025-10-17 17:01:01 +00:00
* mappings are case insensitive * a field is auto mapped only if there is no mapping setting present for that field * "Current user" default value for User field when the user has permission to log time for other users is override by the auto mapped column Patch by Haihan Ji, Yuichi HARADA, and Marius BALTEANU. git-svn-id: http://svn.redmine.org/redmine/trunk@19524 e93f8b46-1217-0410-a6f0-8f06a7374b81
246 lines
7.6 KiB
Ruby
246 lines
7.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Redmine - project management software
|
|
# Copyright (C) 2006-2019 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 IssueImport < Import
|
|
AUTO_MAPPABLE_FIELDS = {
|
|
'tracker' => 'field_tracker',
|
|
'subject' => 'field_subject',
|
|
'description' => 'field_description',
|
|
'status' => 'field_status',
|
|
'priority' => 'field_priority',
|
|
'category' => 'field_category',
|
|
'assigned_to' => 'field_assigned_to',
|
|
'fixed_version' => 'field_fixed_version',
|
|
'is_private' => 'field_is_private',
|
|
'parent_issue_id' => 'field_parent_issue',
|
|
'start_date' => 'field_start_date',
|
|
'due_date' => 'field_due_date',
|
|
'estimated_hours' => 'field_estimated_hours',
|
|
'done_ratio' => 'field_done_ratio'
|
|
}
|
|
|
|
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
|
|
object_ids = saved_items.pluck(:obj_id)
|
|
objects = Issue.where(:id => object_ids).order(:id).preload(:tracker, :priority, :status)
|
|
end
|
|
|
|
# Returns a scope of projects that user is allowed to
|
|
# import issue to
|
|
def allowed_target_projects
|
|
Project.allowed_to(user, :import_issues)
|
|
end
|
|
|
|
def project
|
|
project_id = mapping['project_id'].to_i
|
|
allowed_target_projects.find_by_id(project_id) || allowed_target_projects.first
|
|
end
|
|
|
|
# Returns a scope of trackers that user is allowed to
|
|
# import issue to
|
|
def allowed_target_trackers
|
|
Issue.allowed_target_trackers(project, user)
|
|
end
|
|
|
|
def tracker
|
|
if mapping['tracker'].to_s =~ /\Avalue:(\d+)\z/
|
|
tracker_id = $1.to_i
|
|
allowed_target_trackers.find_by_id(tracker_id)
|
|
end
|
|
end
|
|
|
|
# Returns true if missing categories should be created during the import
|
|
def create_categories?
|
|
user.allowed_to?(:manage_categories, project) &&
|
|
mapping['create_categories'] == '1'
|
|
end
|
|
|
|
# Returns true if missing versions should be created during the import
|
|
def create_versions?
|
|
user.allowed_to?(:manage_versions, project) &&
|
|
mapping['create_versions'] == '1'
|
|
end
|
|
|
|
def mappable_custom_fields
|
|
if tracker
|
|
issue = Issue.new
|
|
issue.project = project
|
|
issue.tracker = tracker
|
|
issue.editable_custom_field_values(user).map(&:custom_field)
|
|
elsif project
|
|
project.all_issue_custom_fields
|
|
else
|
|
[]
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def build_object(row, item)
|
|
issue = Issue.new
|
|
issue.author = user
|
|
issue.notify = !!ActiveRecord::Type::Boolean.new.cast(settings['notifications'])
|
|
|
|
tracker_id = nil
|
|
if tracker
|
|
tracker_id = tracker.id
|
|
elsif tracker_name = row_value(row, 'tracker')
|
|
tracker_id = allowed_target_trackers.named(tracker_name).first.try(:id)
|
|
end
|
|
|
|
attributes = {
|
|
'project_id' => mapping['project_id'],
|
|
'tracker_id' => tracker_id,
|
|
'subject' => row_value(row, 'subject'),
|
|
'description' => row_value(row, 'description')
|
|
}
|
|
if status_name = row_value(row, 'status')
|
|
if status_id = IssueStatus.named(status_name).first.try(:id)
|
|
attributes['status_id'] = status_id
|
|
end
|
|
end
|
|
issue.send :safe_attributes=, attributes, user
|
|
|
|
attributes = {}
|
|
if priority_name = row_value(row, 'priority')
|
|
if priority_id = IssuePriority.active.named(priority_name).first.try(:id)
|
|
attributes['priority_id'] = priority_id
|
|
end
|
|
end
|
|
if issue.project && category_name = row_value(row, 'category')
|
|
if category = issue.project.issue_categories.named(category_name).first
|
|
attributes['category_id'] = category.id
|
|
elsif create_categories?
|
|
category = issue.project.issue_categories.build
|
|
category.name = category_name
|
|
if category.save
|
|
attributes['category_id'] = category.id
|
|
end
|
|
end
|
|
end
|
|
if assignee_name = row_value(row, 'assigned_to')
|
|
if assignee = Principal.detect_by_keyword(issue.assignable_users, assignee_name)
|
|
attributes['assigned_to_id'] = assignee.id
|
|
end
|
|
end
|
|
if issue.project && version_name = row_value(row, 'fixed_version')
|
|
version =
|
|
issue.project.versions.named(version_name).first ||
|
|
issue.project.shared_versions.named(version_name).first
|
|
if version
|
|
attributes['fixed_version_id'] = version.id
|
|
elsif create_versions?
|
|
version = issue.project.versions.build
|
|
version.name = version_name
|
|
if version.save
|
|
attributes['fixed_version_id'] = version.id
|
|
end
|
|
end
|
|
end
|
|
if is_private = row_value(row, 'is_private')
|
|
if yes?(is_private)
|
|
attributes['is_private'] = '1'
|
|
end
|
|
end
|
|
if parent_issue_id = row_value(row, 'parent_issue_id')
|
|
if parent_issue_id.start_with? '#'
|
|
# refers to existing issue
|
|
attributes['parent_issue_id'] = parent_issue_id[1..-1]
|
|
elsif use_unique_id?
|
|
# refers to other row with unique id
|
|
issue_id = items.where(:unique_id => parent_issue_id).first.try(:obj_id)
|
|
|
|
if issue_id
|
|
attributes['parent_issue_id'] = issue_id
|
|
else
|
|
add_callback(parent_issue_id, 'set_as_parent', item.position)
|
|
end
|
|
elsif parent_issue_id =~ /\A\d+\z/
|
|
# refers to other row by position
|
|
parent_issue_id = parent_issue_id.to_i
|
|
|
|
if parent_issue_id > item.position
|
|
add_callback(parent_issue_id, 'set_as_parent', item.position)
|
|
elsif issue_id = items.where(:position => parent_issue_id).first.try(:obj_id)
|
|
attributes['parent_issue_id'] = issue_id
|
|
end
|
|
|
|
else
|
|
# Something is odd. Assign parent_issue_id to trigger validation error
|
|
attributes['parent_issue_id'] = parent_issue_id
|
|
end
|
|
end
|
|
if start_date = row_date(row, 'start_date')
|
|
attributes['start_date'] = start_date
|
|
end
|
|
if due_date = row_date(row, 'due_date')
|
|
attributes['due_date'] = due_date
|
|
end
|
|
if estimated_hours = row_value(row, 'estimated_hours')
|
|
attributes['estimated_hours'] = estimated_hours
|
|
end
|
|
if done_ratio = row_value(row, 'done_ratio')
|
|
attributes['done_ratio'] = done_ratio
|
|
end
|
|
|
|
attributes['custom_field_values'] = issue.custom_field_values.inject({}) do |h, v|
|
|
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, issue)
|
|
end
|
|
h
|
|
end
|
|
|
|
issue.send :safe_attributes=, attributes, user
|
|
|
|
if issue.tracker_id != tracker_id
|
|
issue.tracker_id = nil
|
|
end
|
|
|
|
issue
|
|
end
|
|
|
|
# Callback that sets issue as the parent of a previously imported issue
|
|
def set_as_parent_callback(issue, child_position)
|
|
child_id = items.where(:position => child_position).first.try(:obj_id)
|
|
return unless child_id
|
|
|
|
child = Issue.find_by_id(child_id)
|
|
return unless child
|
|
|
|
child.parent_issue_id = issue.id
|
|
child.save!
|
|
issue.reload
|
|
end
|
|
end
|