Class: Import

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/import.rb

Direct Known Subclasses

IssueImport

Constant Summary

DATE_FORMATS =
[
  '%Y-%m-%d',
  '%d/%m/%Y',
  '%m/%d/%Y',
  '%d.%m.%Y',
  '%d-%m-%Y'
]

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Import

Returns a new instance of Import



38
39
40
41
# File 'app/models/import.rb', line 38

def initialize(*args)
  super
  self.settings ||= {}
end

Instance Method Details

#columns_options(default = nil) ⇒ Object

Returns the headers as an array that can be used for select options



94
95
96
97
# File 'app/models/import.rb', line 94

def columns_options(default=nil)
  i = -1
  headers.map {|h| [h, i+=1]}
end

#file=(arg) ⇒ Object



43
44
45
46
47
48
# File 'app/models/import.rb', line 43

def file=(arg)
  return unless arg.present? && arg.size > 0

  self.filename = generate_filename
  Redmine::Utils.save_upload(arg, filepath)
end

#file_exists?Boolean

Returns true if the file to import exists

Returns:

  • (Boolean)


88
89
90
# File 'app/models/import.rb', line 88

def file_exists?
  filepath.present? && File.exists?(filepath)
end

#filepathObject

Returns the full path of the file to import It is stored in tmp/imports with a random hex as filename



79
80
81
82
83
84
85
# File 'app/models/import.rb', line 79

def filepath
  if filename.present? && filename =~ /\A[0-9a-f]+\z/
    File.join(Rails.root, "tmp", "imports", filename)
  else
    nil
  end
end

#first_rows(count = 4) ⇒ Object

Returns the count first rows of the file (including headers)



122
123
124
125
126
127
128
129
# File 'app/models/import.rb', line 122

def first_rows(count=4)
  rows = []
  read_rows do |row|
    rows << row
    break if rows.size >= count
  end
  rows
end

#headersObject

Returns an array of headers



132
133
134
# File 'app/models/import.rb', line 132

def headers
  first_rows(1).first || []
end

#mappingObject

Returns the mapping options



137
138
139
# File 'app/models/import.rb', line 137

def mapping
  settings['mapping'] || {}
end

#parse_fileObject

Parses the file to import and updates the total number of items



100
101
102
103
104
105
# File 'app/models/import.rb', line 100

def parse_file
  count = 0
  read_items {|row, i| count=i}
  update_attribute :total_items, count
  count
end

#read_itemsObject

Reads the items to import and yields the given block for each item



108
109
110
111
112
113
114
115
116
117
118
119
# File 'app/models/import.rb', line 108

def read_items
  i = 0
  headers = true
  read_rows do |row|
    if i == 0 && headers
      headers = false
      next
    end
    i+= 1
    yield row, i if block_given?
  end
end

#run(options = {}) ⇒ Object

Imports items and returns the position of the last processed item



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'app/models/import.rb', line 142

def run(options={})
  max_items = options[:max_items]
  max_time = options[:max_time]
  current = 0
  imported = 0
  resume_after = items.maximum(:position) || 0
  interrupted = false
  started_on = Time.now

  read_items do |row, position|
    if (max_items && imported >= max_items) || (max_time && Time.now >= started_on + max_time)
      interrupted = true
      break
    end
    if position > resume_after
      item = items.build
      item.position = position

      if object = build_object(row)
        if object.save
          item.obj_id = object.id
        else
          item.message = object.errors.full_messages.join("\n")
        end
      end

      item.save!
      imported += 1
    end
    current = position
  end

  if imported == 0 || interrupted == false
    if total_items.nil?
      update_attribute :total_items, current
    end
    update_attribute :finished, true
    remove_file
  end

  current
end

#saved_itemsObject



189
190
191
# File 'app/models/import.rb', line 189

def saved_items
  items.where("obj_id IS NOT NULL")
end

#set_default_settingsObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'app/models/import.rb', line 50

def set_default_settings
  separator = lu(user, :general_csv_separator)
  if file_exists?
    begin
      content = File.read(filepath, 256)
      separator = [',', ';'].sort_by {|sep| content.count(sep) }.last
    rescue Exception => e
    end
  end
  wrapper = '"'
  encoding = lu(user, :general_csv_encoding)

  date_format = lu(user, "date.formats.default", :default => "foo")
  date_format = DATE_FORMATS.first unless DATE_FORMATS.include?(date_format)

  self.settings.merge!(
    'separator' => separator,
    'wrapper' => wrapper,
    'encoding' => encoding,
    'date_format' => date_format
  )
end

#to_paramObject



73
74
75
# File 'app/models/import.rb', line 73

def to_param
  filename
end

#unsaved_itemsObject



185
186
187
# File 'app/models/import.rb', line 185

def unsaved_items
  items.where(:obj_id => nil)
end