18 |
18 |
require 'active_record'
|
19 |
19 |
require 'iconv' if RUBY_VERSION < '1.9'
|
20 |
20 |
require 'pp'
|
|
21 |
require 'digest/sha1'
|
21 |
22 |
|
22 |
23 |
namespace :redmine do
|
23 |
24 |
desc 'Trac migration script'
|
... | ... | |
76 |
77 |
real_now - @fake_diff.to_i
|
77 |
78 |
end
|
78 |
79 |
def fake(time)
|
|
80 |
time = 0 if time.nil?
|
79 |
81 |
@fake_diff = real_now - time
|
80 |
82 |
res = yield
|
81 |
83 |
@fake_diff = 0
|
... | ... | |
93 |
95 |
# If this attribute is set a milestone has a defined target timepoint
|
94 |
96 |
def due
|
95 |
97 |
if read_attribute(:due) && read_attribute(:due) > 0
|
96 |
|
Time.at(read_attribute(:due)).to_date
|
|
98 |
Time.at(0,read_attribute(:due)).to_date
|
97 |
99 |
else
|
98 |
100 |
nil
|
99 |
101 |
end
|
... | ... | |
101 |
103 |
# This is the real timepoint at which the milestone has finished.
|
102 |
104 |
def completed
|
103 |
105 |
if read_attribute(:completed) && read_attribute(:completed) > 0
|
104 |
|
Time.at(read_attribute(:completed)).to_date
|
|
106 |
Time.at(0,read_attribute(:completed)).to_date
|
105 |
107 |
else
|
106 |
108 |
nil
|
107 |
109 |
end
|
... | ... | |
121 |
123 |
self.table_name = :attachment
|
122 |
124 |
set_inheritance_column :none
|
123 |
125 |
|
124 |
|
def time; Time.at(read_attribute(:time)) end
|
|
126 |
def time; Time.at(0,read_attribute(:time)) end
|
125 |
127 |
|
126 |
128 |
def original_filename
|
127 |
129 |
filename
|
... | ... | |
151 |
153 |
end
|
152 |
154 |
|
153 |
155 |
private
|
154 |
|
def trac_fullpath
|
155 |
|
attachment_type = read_attribute(:type)
|
156 |
|
#replace exotic characters with their hex representation to avoid invalid filenames
|
157 |
|
trac_file = filename.gsub( /[^a-zA-Z0-9\-_\.!~*']/n ) do |x|
|
158 |
|
codepoint = RUBY_VERSION < '1.9' ? x[0] : x.codepoints.to_a[0]
|
159 |
|
sprintf('%%%02x', codepoint)
|
160 |
|
end
|
161 |
|
"#{TracMigrate.trac_attachments_directory}/#{attachment_type}/#{id}/#{trac_file}"
|
|
156 |
def sha1(s)
|
|
157 |
return Digest::SHA1.hexdigest(s)
|
|
158 |
end
|
|
159 |
|
|
160 |
def get_path(ticket_id, filename)
|
|
161 |
t = sha1(ticket_id.to_s)
|
|
162 |
f = sha1(filename)
|
|
163 |
ext = File.extname(filename)
|
|
164 |
a = [ t[0..2], "/", t, "/", f, ext ]
|
|
165 |
return a.join("")
|
|
166 |
end
|
|
167 |
|
|
168 |
def trac_fullpath
|
|
169 |
attachment_type = read_attribute(:type)
|
|
170 |
ticket_id = read_attribute(:id)
|
|
171 |
filename = read_attribute(:filename)
|
|
172 |
path = get_path(ticket_id, filename)
|
|
173 |
"#{TracMigrate.trac_attachments_directory}/#{attachment_type}/#{path}"
|
162 |
174 |
end
|
163 |
175 |
end
|
164 |
176 |
|
... | ... | |
186 |
198 |
read_attribute(:description).blank? ? summary : read_attribute(:description)
|
187 |
199 |
end
|
188 |
200 |
|
189 |
|
def time; Time.at(read_attribute(:time)) end
|
190 |
|
def changetime; Time.at(read_attribute(:changetime)) end
|
|
201 |
def time; Time.at(0,read_attribute(:time)) end
|
|
202 |
def changetime; Time.at(0,read_attribute(:changetime)) end
|
191 |
203 |
end
|
192 |
204 |
|
193 |
205 |
class TracTicketChange < ActiveRecord::Base
|
... | ... | |
198 |
210 |
super.select {|column| column.name.to_s != 'field'}
|
199 |
211 |
end
|
200 |
212 |
|
201 |
|
def time; Time.at(read_attribute(:time)) end
|
|
213 |
def time; Time.at(0,read_attribute(:time)) end
|
202 |
214 |
end
|
203 |
215 |
|
204 |
216 |
TRAC_WIKI_PAGES = %w(InterMapTxt InterTrac InterWiki RecentChanges SandBox TracAccessibility TracAdmin TracBackup TracBrowser TracCgi TracChangeset \
|
... | ... | |
222 |
234 |
TracMigrate::TracAttachment.all(:conditions => ["type = 'wiki' AND id = ?", self.id.to_s])
|
223 |
235 |
end
|
224 |
236 |
|
225 |
|
def time; Time.at(read_attribute(:time)) end
|
|
237 |
def time; Time.at(0,read_attribute(:time)) end
|
226 |
238 |
end
|
227 |
239 |
|
228 |
240 |
class TracPermission < ActiveRecord::Base
|
... | ... | |
283 |
295 |
text = text.gsub(/^(\=+)\s(.+)\s(\=+)/) {|s| "\nh#{$1.length}. #{$2}\n"}
|
284 |
296 |
# External Links
|
285 |
297 |
text = text.gsub(/\[(http[^\s]+)\s+([^\]]+)\]/) {|s| "\"#{$2}\":#{$1}"}
|
|
298 |
# PageOutline
|
|
299 |
text = text.gsub(/\[\[PageOutline\]\]/,"{{>toc}}")
|
|
300 |
# Images
|
|
301 |
text = text.gsub(/\[\[Image\((.*)\)\]\]/,'!\1!')
|
286 |
302 |
# Ticket links:
|
287 |
303 |
# [ticket:234 Text],[ticket:234 This is a test]
|
288 |
304 |
text = text.gsub(/\[ticket\:([^\ ]+)\ (.+?)\]/, '"\2":/issues/show/\1')
|
... | ... | |
327 |
343 |
# We would like to convert the Code highlighting too
|
328 |
344 |
# This will go into the next line.
|
329 |
345 |
shebang_line = false
|
330 |
|
# Regular expression for start of code
|
331 |
|
pre_re = /\{\{\{/
|
332 |
|
# Code highlighting...
|
|
346 |
pre_line = false
|
|
347 |
|
|
348 |
# Reguar expression for start of code
|
|
349 |
pre_re = /^\s*\{\{\{/
|
|
350 |
# Code hightlighing...
|
333 |
351 |
shebang_re = /^\#\!([a-z]+)/
|
334 |
352 |
# Regular expression for end of code
|
335 |
353 |
pre_end_re = /\}\}\}/
|
... | ... | |
339 |
357 |
m_pre = pre_re.match(line)
|
340 |
358 |
if m_pre
|
341 |
359 |
line = '<pre>'
|
|
360 |
pre_line = true
|
342 |
361 |
else
|
343 |
|
m_sl = shebang_re.match(line)
|
344 |
|
if m_sl
|
345 |
|
shebang_line = true
|
346 |
|
line = '<code class="' + m_sl[1] + '">'
|
347 |
|
end
|
348 |
|
m_pre_end = pre_end_re.match(line)
|
349 |
|
if m_pre_end
|
350 |
|
line = '</pre>'
|
351 |
|
if shebang_line
|
352 |
|
line = '</code>' + line
|
|
362 |
if pre_line
|
|
363 |
m_sl = shebang_re.match(line)
|
|
364 |
if m_sl
|
|
365 |
shebang_line = true
|
|
366 |
line = '<code class="' + m_sl[1] + '">'
|
|
367 |
end
|
|
368 |
m_pre_end = pre_end_re.match(line)
|
|
369 |
if m_pre_end
|
|
370 |
line = '</pre>'
|
|
371 |
if shebang_line
|
|
372 |
line = '</code>' + line
|
|
373 |
end
|
|
374 |
pre_line = false
|
353 |
375 |
end
|
354 |
376 |
end
|
355 |
377 |
end
|
... | ... | |
572 |
594 |
# Attachments
|
573 |
595 |
page.attachments.each do |attachment|
|
574 |
596 |
next unless attachment.exist?
|
575 |
|
next if p.attachments.find_by_filename(attachment.filename.gsub(/^.*(\\|\/)/, '').gsub(/[^\w\.\-]/,'_')) #add only once per page
|
|
597 |
next if p.attachments.find_by_filename(attachment.filename.gsub(/[\/\?\%\*\:\|\"\'<>\n\r]+/, '_')) #add only once per page
|
|
598 |
|
576 |
599 |
attachment.open {
|
577 |
600 |
a = Attachment.new :created_on => attachment.time
|
578 |
601 |
a.file = attachment
|
... | ... | |
665 |
688 |
mattr_reader :trac_directory, :trac_adapter, :trac_db_host, :trac_db_port, :trac_db_name, :trac_db_schema, :trac_db_username, :trac_db_password
|
666 |
689 |
|
667 |
690 |
def self.trac_db_path; "#{trac_directory}/db/trac.db" end
|
668 |
|
def self.trac_attachments_directory; "#{trac_directory}/attachments" end
|
|
691 |
def self.trac_attachments_directory; "#{trac_directory}/files/attachments" end
|
669 |
692 |
|
670 |
693 |
def self.target_project_identifier(identifier)
|
671 |
694 |
project = Project.find_by_identifier(identifier)
|
... | ... | |
781 |
804 |
end
|
782 |
805 |
end
|
783 |
806 |
end
|
|
807 |
|