summaryrefslogtreecommitdiffstats
path: root/app/models/time_entry_import.rb
blob: 01fde348840362410dca7a2d260a5a858ebcf091 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# frozen_string_literal: true

# Redmine - project management software
# Copyright (C) 2006-  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 TimeEntryImport < Import
  AUTO_MAPPABLE_FIELDS = {
    'activity' => 'field_activity',
    'user' => 'field_user',
    'issue_id' => 'field_issue',
    'spent_on' => 'field_spent_on',
    'hours' => 'field_hours',
    'comments' => 'field_comments'
  }

  def self.menu_item
    :time_entries
  end

  def self.authorized?(user)
    user.allowed_to?(:import_time_entries, nil, :global => true) && user.allowed_to?(:log_time, nil, :global => true)
  end

  # Returns the objects that were imported
  def saved_objects
    TimeEntry.where(:id => saved_items.pluck(:obj_id)).order(:id).preload(:activity, :project, :issue => [:tracker, :priority, :status])
  end

  def mappable_custom_fields
    TimeEntryCustomField.all
  end

  def allowed_target_projects
    Project.allowed_to(user, :log_time).order(:lft)
  end

  def allowed_target_activities
    project.activities
  end

  def allowed_target_users
    users = []
    if project
      users = project.members.active.preload(:user)
      users = users.map(&:user).select{|u| u.allowed_to?(:log_time, project)}
    end
    users << User.current if User.current.logged? && !users.include?(User.current)
    users
  end

  def project
    project_id = mapping['project_id'].to_i
    allowed_target_projects.find_by_id(project_id) || allowed_target_projects.first
  end

  def activity
    if mapping['activity'].to_s =~ /\Avalue:(\d+)\z/
      activity_id = $1.to_i
      allowed_target_activities.find_by_id(activity_id)
    end
  end

  def user_value
    if mapping['user'].to_s =~ /\Avalue:(\d+)\z/
      $1.to_i
    end
  end

  private

  def build_object(row, item)
    object = TimeEntry.new
    object.author = user

    activity_id = nil
    if activity
      activity_id = activity.id
    elsif activity_name = row_value(row, 'activity')
      activity_id = allowed_target_activities.named(activity_name).first.try(:id)
    end

    user_id = nil
    if user.allowed_to?(:log_time_for_other_users, project)
      if user_value
        user_id = user_value
      elsif user_name = row_value(row, 'user')
        user_id = Principal.detect_by_keyword(allowed_target_users, user_name).try(:id)
      end
    else
      user_id = user.id
    end

    attributes = {
      :activity_id => activity_id,
      :author_id   => user.id,
      :user_id     => user_id,

      :spent_on    => row_date(row, 'spent_on'),
      :hours       => row_value(row, 'hours'),
      :comments    => row_value(row, 'comments')
    }

    if issue_id = row_value(row, 'issue_id').presence
      attributes[:issue_id] = issue_id
      object.project = issue_project(issue_id)
    else
      attributes[:project_id] = project.id
      object.project = project
    end

    attributes['custom_field_values'] = object.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, object)
      end
      h
    end

    object.send(:safe_attributes=, attributes, user)
    object
  end

  def issue_project(issue_id)
    if issue_project_id = Issue.where(id: issue_id).limit(1).pick(:project_id)
      (@projects_cache ||= {})[issue_project_id] ||= allowed_target_projects.find_by_id(issue_project_id)
    end
  end
end