migrate_from_scarab_patch.diff

Fabian Buch, 2009-03-07 14:16

Download (31.7 KB)

View differences:

lib/tasks/migrate_from_scarab.rake (revision 0)
1

  
2
require 'active_record'
3
require 'iconv'
4
require 'pp'
5

  
6
$DBG = false
7
$stdout.sync = true
8
ActiveRecord::Base.record_timestamps = false
9

  
10
namespace :redmine do
11
  desc 'Scarab migration script'
12
  task :migrate_from_scarab => :environment do
13
    
14
    module ScarabMigrate
15
        TICKET_MAP = []
16

  
17
        DEFAULT_STATUS = IssueStatus.default
18
        assigned_status = IssueStatus.find_by_position(2)
19
        resolved_status = IssueStatus.find_by_position(3)
20
        feedback_status = IssueStatus.find_by_position(4)
21
        closed_status = IssueStatus.find :first, :conditions => { :is_closed => true }
22
        STATUS_MAPPING = {'New' => DEFAULT_STATUS,
23
                          'Reopened' => feedback_status,
24
                          'Assigned' => assigned_status,
25
                          'Resolved' => resolved_status,
26
                          'Unconfirmed' => feedback_status,
27
                          'Verified' => closed_status,
28
                          'Closed' => closed_status,
29
                          'Fixed'      => closed_status,
30
                          'Invalid'    => closed_status,
31
                          'Wontfix'    => closed_status,
32
                          'Later'      => feedback_status,
33
                          'Remind'     => feedback_status,
34
                          'Duplicate'  => closed_status,
35
                          'Worksforme' => closed_status,
36
                          'Moved'      => closed_status,
37
                          'Init'       => DEFAULT_STATUS,
38
                          'Assigned'   => assigned_status,
39
                          'Assigend'   => assigned_status,
40
                          'Missing Data' => feedback_status
41
                          }
42
        
43
        priorities = Enumeration.get_values('IPRI')
44
        DEFAULT_PRIORITY = priorities[0]
45
        PRIORITY_MAPPING = {'lowest' => priorities[0],
46
                            'low' => priorities[0],
47
                            'normal' => priorities[1],
48
                            'high' => priorities[2],
49
                            'highest' => priorities[3],
50
                            # ---
51
                            'trivial' => priorities[0],
52
                            'minor' => priorities[1],
53
                            'major' => priorities[2],
54
                            'critical' => priorities[3],
55
                            'blocker' => priorities[4],
56
                            # --- 7
57
                            'Low' => priorities[0],
58
                            'Undecided' => priorities[0],
59
                            'Medium' => priorities[1],
60
                            'High' => priorities[2],
61
                            # --- 9
62
                            'Blocker'     => priorities[4],
63
                            'Critical'    => priorities[3],
64
                            'Major'       => priorities[2],
65
                            'Normal'      => priorities[1],
66
                            'Minor'       => priorities[0],
67
                            'Trivial'     => priorities[0],
68
                            'Enhancement' => priorities[0],
69
                            'Cosmetic'    => priorities[0],
70
                            'Serious'     => priorities[3],
71
                            'Undecided'   => priorities[0]
72
                            }
73
                            
74
        
75
        TRACKER_BUG = Tracker.find_by_position(1)
76
        TRACKER_FEATURE = Tracker.find_by_position(2)
77
        DEFAULT_TRACKER = TRACKER_BUG
78
        TRACKER_MAPPING = {'defect' => TRACKER_BUG,
79
                           'Enhancement' => TRACKER_FEATURE,
80
                           'task' => TRACKER_FEATURE,
81
                           'patch' =>TRACKER_FEATURE
82
                           }
83
        
84
        roles = Role.find(:all, :conditions => {:builtin => 0}, :order => 'position ASC')
85
        manager_role = roles[0]
86
        developer_role = roles[1]
87
        reporter_role = roles[2]
88
        DEFAULT_ROLE = roles.last
89
        ROLE_MAPPING = {'admin' => manager_role,
90
                        'developer' => developer_role,
91
                        'reporter' => reporter_role
92
                        }
93
        ATTRIBUTE_NAMES = {
94
           :NullAttribute   =>  0,
95
           :Description     =>  1,
96
           :AssignedTo      =>  2,
97
           :Status          =>  3,
98
           :Resolution      =>  4,
99
           :Platform        =>  5,
100
           :OperatingSystem =>  6,
101
           :Priority        =>  7,
102
           :Vote            =>  8,
103
           :Severity        =>  9,
104
           :AssignedCC      => 13,
105
           :Summary         => 11,
106
           :FunctionalArea  => 12,
107
           :DueTime         => 10022,
108
           :Version         => 10000,
109
           :Projekt_type    => 10020 # Internes / Externes Projekt           
110
        }
111
        ATTACHMENT_TYPES = {
112
          :ATTACHMENT => 1,
113
          :COMMENT => 2,
114
          :URL => 3,
115
          :MODIFICATION => 4
116
        }       
117

  
118
        class ScarabProject < ActiveRecord::Base
119
          set_table_name :SCARAB_MODULE
120
          set_primary_key :MODULE_ID
121
          belongs_to :owner,
122
                     :class_name => "ScarabUser",
123
                     :foreign_key => :OWNER_ID
124
          belongs_to :parent,
125
                     :class_name => "ScarabProject",
126
                     :foreign_key => :PARENT_ID
127

  
128
          def id
129
            read_attribute(:MODULE_ID)
130
          end
131
          
132
          def name
133
            read_attribute(:MODULE_NAME)[0..29]
134
          end
135
        
136
          def identifier
137
            prefix = ""
138
            if parent.name.split("-").size > 1
139
      	      prefix = parent.name.split("-")[0].downcase + "-"
140
    	      end
141
      	    
142
            idt = prefix + read_attribute(:MODULE_CODE)
143
            if idt.size > 2
144
              idt.underscore[0..19].gsub(/[^a-z0-9\-]/, '-')
145
            else
146
              idt.underscore[0..19].gsub(/[^a-z0-9\-]/, '-') + "-module"
147
            end
148
          end
149
          
150
          def description
151
            read_attribute(:MODULE_DESCRIPTION)
152
          end
153
          
154
          def parent_id
155
            read_attribute(:PARENT_ID)
156
          end
157
          
158
          def owner_id
159
            read_attribute(:OWNER_ID)
160
          end
161
          
162
          def deleted?
163
            read_attribute(:DELETED).to_i == 1 ? true : false
164
          end
165
        end
166
        
167
        class ScarabIssue < ActiveRecord::Base
168
          set_table_name :SCARAB_ISSUE
169
          set_primary_key :ISSUE_ID
170
          
171
          belongs_to :project,
172
                     :class_name => "ScarabProject",
173
                     :foreign_key => :MODULE_ID
174
          has_many :attribute_values,
175
                   :class_name => "ScarabIssueAttributeValue",
176
                   :foreign_key => :ISSUE_ID
177
          has_many :activities,
178
                   :class_name => "ScarabActivity",
179
                   :foreign_key => :ISSUE_ID
180
          has_many :attachments,
181
                   :class_name => "ScarabAttachment",
182
                   :foreign_key => :ISSUE_ID
183

  
184
          def id
185
            read_attribute(:ISSUE_ID)
186
          end
187
          
188
          def project_id
189
            read_attribute(:MODULE_ID)
190
          end
191
          
192
          def scarab_number
193
            "(_ScarabId_ *#" + read_attribute(:ID_PREFIX).to_s + read_attribute(:ID_COUNT).to_s + "*) "
194
          end
195
          
196
          def id_prefix
197
            read_attribute(:ID_PREFIX)
198
          end
199
          
200
          def id_count
201
            read_attribute(:ID_COUNT)
202
          end
203

  
204
          def created_transaction_id
205
            read_attribute(:CREATED_TRANS_ID)
206
          end
207
          
208
          def updated_transaction_id
209
            read_attribute(:LAST_TRANS_ID)
210
          end
211
          
212
          def deleted?
213
            read_attribute(:DELETED).to_i == 1 ? true : false
214
          end
215
          
216
          def moved?
217
            read_attribute(:MOVED).to_i == 1 ? true : false
218
          end
219
        end
220
        
221
        class ScarabIssueAttributeValue < ActiveRecord::Base
222
          set_table_name :SCARAB_ISSUE_ATTRIBUTE_VALUE
223
          belongs_to :issue,
224
                     :class_name => "ScarabIssue",
225
                     :foreign_key => :ISSUE_ID
226

  
227
          def value
228
            read_attribute(:VALUE)
229
          end
230
          
231
          def user_id
232
            read_attribute(:USER_ID)
233
          end
234
        end
235
        
236
        class ScarabAttribute < ActiveRecord::Base
237
          set_table_name :SCARAB_ATTRIBUTE
238
          set_primary_key :ATTRIBUTE_ID
239
          
240
          def name
241
            read_attribute(:ATTRIBUTE_NAME)
242
          end
243
        end
244
        
245
        class ScarabActivity < ActiveRecord::Base
246
          set_table_name :SCARAB_ACTIVITY
247
          set_primary_key :ACTIVITY_ID
248
          belongs_to :issue,
249
                     :class_name => "ScarabIssue",
250
                     :foreign_key => :ISSUE_ID
251
          belongs_to :transaction,
252
                     :class_name => "ScarabTransaction",
253
                     :foreign_key => :TRANSACTION_ID
254
          belongs_to :attribute,
255
                     :class_name => "ScarabAttribute",
256
                     :foreign_key => :ATTRIBUTE_ID
257

  
258
          def old_value
259
            read_attribute(:OLD_VALUE)
260
          end
261

  
262
          def new_value
263
            read_attribute(:NEW_VALUE)
264
          end
265

  
266
          def type
267
            read_attribute(:ACTIVITY_TYPE)
268
          end
269
          
270
          def attribute_id
271
            read_attribute(:ATTRIBUTE_ID)
272
          end
273
        end
274
        
275
        class ScarabAttachment < ActiveRecord::Base
276
          set_table_name :SCARAB_ATTACHMENT
277
          set_primary_key :ATTACHMENT_ID
278
          belongs_to :issue, :class_name => "ScarabIssue", :foreign_key => :ISSUE_ID
279
          belongs_to :creator, :class_name => "ScarabUser", :foreign_key => :CREATED_BY
280
          belongs_to :updator, :class_name => "ScarabUser", :foreign_key => :MODIFIED_BY
281

  
282
          def name
283
            read_attribute(:ATTACHMENT_NAME)
284
          end
285

  
286
          def data
287
            read_attribute(:ATTACHMENT_DATA)
288
          end
289

  
290
          def attachment_type_id
291
            read_attribute(:ATTACHMENT_TYPE_ID)
292
          end
293

  
294
          def original_filename
295
            orig_file_name = ScarabMigrate.encode(read_attribute(:ATTACHMENT_FILE_PATH))
296
            scarab_number = issue.id_prefix + issue.id_count.to_s
297
            scarab_number + "_" + id.to_s + "_" + orig_file_name
298
          end
299

  
300
          def content_type
301
            read_attribute(:ATTACHMENT_MIME_TYPE)
302
          end
303
          
304
          def exist?
305
            File.file? scarab_fullpath
306
          end
307

  
308
          def read
309
            File.open("#{scarab_fullpath}").read
310
          end
311
          
312
          def size
313
            File.new("#{scarab_fullpath}").stat.blksize
314
          end
315

  
316
          def description
317
            read_attribute(:ATTACHMENT_NAME)
318
          end
319

  
320
          def updated_date
321
            read_attribute(:MODIFIED_DATE)
322
          end
323

  
324
          def created_date
325
            read_attribute(:CREATED_DATE)
326
          end
327

  
328
          def deleted?
329
            read_attribute(:DELETED) == 1 ? true : false
330
          end
331
        private
332
          def scarab_fullpath
333
            full_path = []
334
            full_path << "#{ScarabMigrate.scarab_attachments_directory}"
335
            full_path << "mod" + issue.project_id.to_s
336
            full_path << "0" # TODO investigate what's "0" in scarab dir path
337
            full_path << "#{original_filename}"
338
            full_path.join(File::SEPARATOR)
339
          end
340
        end
341

  
342
        class ScarabUser < ActiveRecord::Base
343
          set_table_name :TURBINE_USER
344
          has_many :projects,
345
                   :class_name => "ScarabProject",
346
                   :foreign_key => :OWNER_ID
347
          has_many :transactions,
348
                   :class_name => "ScarabTransaction",
349
                   :foreign_key => :CREATED_BY
350
          
351
          set_primary_key :USER_ID
352
          
353
          def id
354
            read_attribute(:USER_ID)
355
          end
356
          
357
          def username
358
            read_attribute(:LOGIN_NAME)
359
          end
360
          
361
          def firstname
362
            read_attribute(:FIRST_NAME)
363
          end
364
          
365
          def lastname
366
            read_attribute(:LAST_NAME)
367
          end
368
          
369
          def email
370
            read_attribute(:EMAIL)
371
          end
372
          
373
          def last_visit
374
            read_attribute(:LAST_LOGIN)
375
          end
376
          
377
          def deleted?
378
            read_attribute(:CONFIRM_VALUE) == 'DELETED'
379
          end
380
        end
381
        
382
        class ScarabTransaction < ActiveRecord::Base
383
          set_table_name :SCARAB_TRANSACTION
384
          belongs_to :creator,
385
                     :class_name => "ScarabUser",
386
                     :foreign_key => :CREATED_BY
387

  
388
          set_primary_key :TRANSACTION_ID
389

  
390
          def id
391
            read_attribute(:TRANSACTION_ID)
392
          end
393

  
394
          def date
395
            read_attribute(:CREATED_DATE)
396
          end
397
        end
398

  
399
        def self.connection_params
400
          if %w(sqlite sqlite3).include?(scarab_adapter)
401
            {:adapter => scarab_adapter, 
402
             :database => scarab_db_path}
403
          else
404
            {:adapter => scarab_adapter,
405
             :database => scarab_db_name,
406
             :host => scarab_db_host,
407
             :port => scarab_db_port,
408
             :username => scarab_db_username,
409
             :password => scarab_db_password
410
            }
411
          end
412
        end
413
        
414
        def self.set_scarab_directory(path)
415
          @@scarab_directory = path
416
          raise "This directory doesn't exist!" unless File.directory?(path)
417
          raise "#{scarab_attachments_directory} doesn't exist!" unless File.directory?(scarab_attachments_directory)
418
          @@scarab_directory
419
        rescue Exception => e
420
          puts e
421
          return false
422
        end
423

  
424
        def self.scarab_directory
425
          @@scarab_directory
426
        end
427
        
428
        def self.set_scarab_adapter(adapter)
429
          return false if adapter.blank?
430
          raise "Unknown adapter: #{adapter}!" unless %w(sqlite sqlite3 mysql postgresql).include?(adapter)
431
          # If adapter is sqlite or sqlite3, make sure that scarab.db exists
432
          raise "#{scarab_db_path} doesn't exist!" if %w(sqlite sqlite3).include?(adapter) && !File.exist?(scarab_db_path)
433
          @@scarab_adapter = adapter
434
        rescue Exception => e
435
          puts e
436
          return false
437
        end
438

  
439
        def self.set_scarab_db_host(host)
440
          return nil if host.blank?
441
          @@scarab_db_host = host
442
        end
443

  
444
        def self.set_scarab_db_port(port)
445
          return nil if port.to_i == 0
446
          @@scarab_db_port = port.to_i
447
        end
448

  
449
        def self.set_scarab_db_name(name)
450
          return nil if name.blank?
451
          @@scarab_db_name = name
452
        end
453

  
454
        def self.set_scarab_db_username(username)
455
          @@scarab_db_username = username
456
        end
457

  
458
        def self.set_scarab_db_password(password)
459
          @@scarab_db_password = password
460
        end
461

  
462
        def self.encoding(charset)
463
          @ic = Iconv.new('UTF-8', charset)
464
        rescue Iconv::InvalidEncoding
465
          puts "Invalid encoding!"
466
          return false
467
        end
468

  
469
        mattr_reader :scarab_directory, :scarab_adapter, :scarab_db_host, :scarab_db_port, :scarab_db_name, :scarab_db_username, :scarab_db_password
470

  
471
        def self.scarab_db_path; "#{scarab_directory}/db/scarab.db" end
472
        def self.scarab_attachments_directory 
473
          "#{scarab_directory}/" # TODO set correctly
474
        end
475

  
476
        def self.establish_connection
477
          constants.each do |const|
478
            klass = const_get(const)
479
            next unless klass.respond_to? 'establish_connection'
480
            klass.establish_connection connection_params
481
          end
482
        end
483
        
484
        def self.migrate
485
          establish_connection
486
          
487
          # Users
488
          print "Migrating users"
489
          #User.delete_all "login <> 'admin'"
490
          users_map = {}
491
          users_migrated = 0
492
          ScarabUser.find(:all).each do |user|
493
            next if user.deleted?
494
        	  u = User.new :firstname => encode(user.firstname), 
495
        	  			       :lastname => encode(user.lastname),
496
        	  			       :mail => user.email,
497
        	  			       :last_login_on => user.last_visit
498
        	  u.login = user.username
499
        	  u.password = 'scarab'
500
        	  #u.admin = true if user.access_level == 90
501
        	  next unless u.save
502
        	  users_migrated += 1
503
        	  users_map[user.id] = u.id
504
        	  print '.'
505
          end
506
          puts
507
          
508
          
509
          # Projects
510
          print "Migrating projects"
511
          #Project.destroy_all
512
          projects_map = {}
513
          versions_map = {}
514
          categories_map = {}
515
          ScarabProject.find(:all, :order => :MODULE_ID).each do |project|
516
        	  next if project.deleted?
517
        	  next if project.id == 0 # Global Scarab parent project, do not migrate
518
        	  p = Project.new :name => encode(project.name), 
519
                            :description => encode(project.description),
520
                            :created_on => Time.now,
521
                            :updated_on => Time.now
522

  
523
        	  # Project parent relationship
524
        	  parent = ScarabProject.find(:first, :conditions => {:MODULE_ID => project.parent_id})
525
        	  unless project.parent_id == 0
526
        	    p.parent_id = Project.find(:first, :conditions => {:identifier => parent.identifier}).id
527
      	    end
528

  
529
      	    p.identifier = project.identifier
530

  
531
            print "\nCreate project: " + project.name + " [yN] "
532
            answer = STDIN.gets.chomp!
533
            next unless answer == "y"
534
            
535
        	  unless p.save
536
        	    p p.errors if $DBG
537
        	    next
538
      	    end
539
        	  projects_map[project.id] = p.id
540
        	  p.enabled_module_names = ['issue_tracking', 'news', 'wiki']
541
            p.trackers << TRACKER_BUG
542
            p.trackers << TRACKER_FEATURE
543
        	  puts "created with identifier: " + p.identifier
544
        	  
545
        	  # Project Owner as manager member
546
        	  scarab_owner = ScarabUser.find(:first, :conditions => {:USER_ID => project.owner_id})
547
        	  owner = Member.new
548
        	  owner.role = ROLE_MAPPING['admin']
549
        	  owner.user = User.find(:first, :conditions => {:login => scarab_owner.username})
550
        	  owner.project = p
551
        	  owner.save
552
          end	
553
          puts
554
          
555
          
556
          # Issues
557
          print "Migrating issues"
558
          issues_map = {}
559
          moved = 0
560
          deleted = 0
561
          no_scarab_project = 0
562
          no_project = 0
563
          not_validated = 0
564
          issue_counter = 0
565
          ScarabIssue.find(:all, :order => 'ISSUE_ID ASC').each do |issue|
566
            issue_counter += 1
567
            if issue.deleted?
568
              deleted += 1
569
              next
570
            end
571
            if issue.moved?
572
              moved += 1
573
              next
574
            end
575
            scarab_project = ScarabProject.find(:first, :conditions => {:MODULE_ID => issue.project_id})
576
            unless scarab_project
577
              no_scarab_project += 1
578
              next
579
            end
580
            project = Project.find(:first, :conditions => {:identifier => scarab_project.identifier})
581
            unless project
582
              no_project += 1
583
              next
584
            end
585
            i = Issue.new :project_id => project.id
586

  
587
            description = ScarabIssueAttributeValue.find(:first, :conditions => {
588
              :ISSUE_ID => issue.id,
589
              :ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Description]
590
            })
591
            summary = ScarabIssueAttributeValue.find(:first, :conditions => {
592
              :ISSUE_ID => issue.id,
593
              :ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Summary]
594
            })
595
            if summary && summary.value && summary.value.size > 1
596
              i.subject = encode(summary.value)
597
            else
598
              i.subject = encode(description.value[0..40])
599
            end
600
            if description
601
              i.description = issue.scarab_number.to_s + encode(description.value)
602
            else
603
              i.description = issue.scarab_number.to_s + encode(summary.value)
604
            end
605
            
606
            status = ScarabIssueAttributeValue.find(:first, :conditions => {
607
              :ISSUE_ID => issue.id,
608
              :ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Status]
609
            })
610
            i.status = status ? STATUS_MAPPING[status.value] : DEFAULT_STATUS
611
            resolution = ScarabIssueAttributeValue.find(:first, :conditions => {
612
              :ISSUE_ID => issue.id,
613
              :ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Resolution]
614
            })
615
            i.status = STATUS_MAPPING[resolution.value] if resolution && resolution.value
616

  
617
            severity = ScarabIssueAttributeValue.find(:first, :conditions => {
618
              :ISSUE_ID => issue.id,
619
              :ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Severity]
620
            })
621
            if severity
622
              i.priority = PRIORITY_MAPPING[severity.value]
623
              i.tracker = TRACKER_MAPPING[severity.value] || TRACKER_BUG
624
            else
625
              priority = ScarabIssueAttributeValue.find(:first, :conditions => {
626
                :ISSUE_ID => issue.id,
627
                :ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Priority]
628
              })
629
              i.priority = PRIORITY_MAPPING[priority.value] if priority
630
              i.tracker = TRACKER_BUG
631
            end
632

  
633
            created_transaction = ScarabTransaction.find(:first, :conditions => {
634
              :TRANSACTION_ID => issue.created_transaction_id
635
            })
636
            scarab_author = ScarabUser.find(:first, :conditions => {:USER_ID => created_transaction.creator.id})
637
            i.author = User.find(:first, :conditions => {:login => scarab_author.username})
638
            i.author ||= User.find(:first, :conditions => {:login => 'Admin'})
639
            i.author ||= User.find(:first)
640
            updated_transaction = ScarabTransaction.find(:first, :conditions => {
641
              :TRANSACTION_ID => issue.updated_transaction_id
642
            })
643
            i.created_on = created_transaction ? created_transaction.date : Time.now
644
            i.updated_on = updated_transaction ? updated_transaction.date : Time.now 
645
            
646
            assigned_tos = ScarabIssueAttributeValue.find(:all, :conditions => {
647
              :ISSUE_ID => issue.id,
648
              :ATTRIBUTE_ID => ATTRIBUTE_NAMES[:AssignedTo]
649
            })
650
            assigned_ccs = ScarabIssueAttributeValue.find(:all, :conditions => {
651
              :ISSUE_ID => issue.id,
652
              :ATTRIBUTE_ID => ATTRIBUTE_NAMES[:AssignedCC]
653
            })
654
            scarab_assignee = ScarabUser.find(:first, :conditions => {:USER_ID => assigned_tos[0].user_id}) if assigned_tos[0]
655
          	i.assigned_to = User.find(:first, :conditions => {:login => scarab_assignee.username}) if scarab_assignee
656
            
657
            # Assigned to as 'developer' Member of current Project
658
            assigned_tos.each do |assigned_to|
659
          	  s_assignee = ScarabUser.find(:first, :conditions => {:USER_ID => assigned_to.user_id})
660
          	  developer = Member.new
661
          	  developer.role = ROLE_MAPPING['developer']
662
          	  r_user = User.find(:first, :conditions => {:login => s_assignee.username})
663
          	  developer.user = r_user
664
          	  developer.project = project
665
                  #i.add_watcher(r_user)
666
          	  next unless developer.save
667
            end
668
            
669
            # Assigned to as 'reporter' Member of current Project
670
            assigned_ccs.each do |assigned_cc|
671
          	  s_assignee = ScarabUser.find(:first, :conditions => {:USER_ID => assigned_cc.user_id})
672
          	  reporter = Member.new
673
          	  reporter.role = ROLE_MAPPING['reporter']
674
          	  r_user = User.find(:first, :conditions => {:login => s_assignee.username})
675
          	  reporter.user = r_user
676
          	  reporter.project = project
677
          	  #i.add_watcher(r_user)
678
          	  next unless reporter.save
679
            end
680
            
681
            due_date = ScarabIssueAttributeValue.find(:first, :conditions => {
682
              :ISSUE_ID => issue.id,
683
              :ATTRIBUTE_ID => ATTRIBUTE_NAMES[:DueTime]
684
            })
685
            i.due_date = due_date if due_date
686

  
687
            unless i.save
688
              p i.errors if $DBG
689
              not_validated += 1
690
              next
691
            end
692

  
693
            # Issue Watchers (to)
694
            assigned_tos.each do |assigned_to|
695
          	  s_assignee = ScarabUser.find(:first, :conditions => {:USER_ID => assigned_to.user_id})
696
          	  r_user = User.find(:first, :conditions => {:login => s_assignee.username})
697
                  i.add_watcher(r_user)
698
            end
699
            # Issue Watchers (cc)
700
            assigned_ccs.each do |assigned_cc|
701
          	  s_assignee = ScarabUser.find(:first, :conditions => {:USER_ID => assigned_cc.user_id})
702
          	  r_user = User.find(:first, :conditions => {:login => s_assignee.username})
703
          	  i.add_watcher(r_user)
704
            end
705
            
706
            # Issue Attachments (Comments and Attachments)
707
            issue.attachments.each do |a|
708
              next if a.deleted?
709
              if a.attachment_type_id == ATTACHMENT_TYPES[:COMMENT] || 
710
                a.attachment_type_id == ATTACHMENT_TYPES[:MODIFICATION]
711
                j = Journal.new
712
                next unless encode(a.data).size > 0
713
                j.notes = encode(a.data)
714
                if r_user = User.find(:first, :conditions => {:login => a.creator.username})
715
                  j.user = r_user
716
                elsif r_adminuser = User.find(:first, :conditions => {:login => 'Admin'})
717
                  j.user = r_adminuser
718
                else
719
                  j.user = User.find(:first)
720
                end
721
                j.created_on = a.created_date
722
                j.journalized = i
723
                unless j.save
724
                  p j.errors if $DBG
725
                  next
726
                end
727
              elsif a.attachment_type_id == ATTACHMENT_TYPES[:ATTACHMENT]
728
                r_attachement = Attachment.new :created_on => a.created_date
729
                if r_user = User.find(:first, :conditions => {:login => a.creator.username})
730
                  r_attachement.author = r_user
731
                elsif r_adminuser = User.find(:first, :conditions => {:login => 'Admin'})
732
                  r_attachement.author = r_adminuser
733
                else
734
                  r_attachement.author = User.find(:first)
735
                end
736
                r_attachement.container = i
737
                r_attachement.description = a.name
738
                r_attachement.file = a
739
                r_attachement.save
740
              end
741
            end
742
            
743
            # Issue Activities
744
            notes_transaction_map = {}
745
            issue.activities.each do |a|
746
              if a.type == "user_attribute_changed" || a.type == "attribute_changed"
747
                if !a.new_value || a.new_value.size == 0
748
                  next
749
                end
750
                notes_transaction_map[a.transaction] = [] unless notes_transaction_map[a.transaction]
751
                attribute_name = "* *" + a.attribute.name + "*: "
752
                from = "_changed from_ " + encode(a.old_value) if a.old_value
753
                to = " _to_ " + encode(a.new_value) if a.new_value
754
                notes_transaction_map[a.transaction] << attribute_name.to_s + from.to_s + to.to_s
755
              end
756
            end
757
            notes_transaction_map.each do |t, notes|
758
              j = Journal.new
759
              j.notes = notes.join("\n")
760
              if r_user = User.find(:first, :conditions => {:login => t.creator.username})
761
                j.user = r_user
762
              elsif r_adminuser = User.find(:first, :conditions => {:login => 'Admin'})
763
                j.user = r_adminuser
764
              else
765
                j.user = User.find(:first)
766
              end
767
              j.created_on = t.date
768
              j.journalized = i
769
              unless j.save
770
                p j.errors if $DBG
771
                next
772
              end
773
            end
774

  
775
            print "."
776
          end
777
          puts
778
          
779
          # Summary
780
          puts
781
          puts "i moved: #{moved}" if $DBG
782
          puts "i deleted: #{deleted}" if $DBG
783
          puts "i no_project: #{no_project}" if $DBG
784
          puts "i no_scarab_project: #{no_scarab_project}" if $DBG
785
          puts "i not_validated: #{not_validated}" if $DBG
786
          puts "i issue_counter: #{issue_counter}" if $DBG
787
          puts "Users:          #{users_migrated}/#{ScarabUser.count}"
788
          puts "Projects:        #{Project.count}/#{ScarabProject.count}"
789
          puts "Issues:            #{Issue.count}/#{ScarabIssue.count}"
790
          puts "Comments and Attachments:   #{Journal.count + Attachment.count}/#{ScarabAttachment.count + ScarabActivity.count}"
791
        end
792
        
793
      def self.encoding(charset)
794
        @ic = Iconv.new('UTF-8', charset)
795
      #rescue Iconv::InvalidEncoding
796
      #  return false      
797
      end
798
        
799
    private
800
      def self.encode(text)
801
        @ic.iconv text
802
      rescue
803
        text
804
      end
805
    end
806

  
807
    puts
808
    if Redmine::DefaultData::Loader.no_data?
809
      puts "Redmine configuration need to be loaded before importing data."
810
      puts "Please, run this first:"
811
      puts
812
      puts "  rake redmine:load_default_data RAILS_ENV=\"#{ENV['RAILS_ENV']}\""
813
      exit
814
    end
815

  
816
    puts "WARNING: new projects will be added to Redmine during this process."
817
    print "Are you sure you want to continue ? [y/N] "
818
    break unless STDIN.gets.match(/^y$/i)  
819
    puts
820

  
821
    def prompt(text, options = {}, &block)
822
      default = options[:default] || ''
823
      while true
824
        print "#{text} [#{default}]: "
825
        value = STDIN.gets.chomp!
826
        value = default if value.blank?
827
        break if yield value
828
      end
829
    end
830

  
831
    DEFAULT_PORTS = {'mysql' => 3306, 'postgresql' => 5432}
832

  
833
    prompt('Scarab attachments directory') {|directory| ScarabMigrate.set_scarab_directory directory.strip}
834
    prompt('Scarab database adapter (sqlite, sqlite3, mysql, postgresql)', :default => 'mysql') {|adapter| ScarabMigrate.set_scarab_adapter adapter}
835
    unless %w(sqlite sqlite3).include?(ScarabMigrate.scarab_adapter)
836
      prompt('Scarab database host', :default => 'localhost') {|host| ScarabMigrate.set_scarab_db_host host}
837
      prompt('Scarab database port', :default => DEFAULT_PORTS[ScarabMigrate.scarab_adapter]) {|port| ScarabMigrate.set_scarab_db_port port}
838
      prompt('Scarab database name', :default => 'scarab') {|name| ScarabMigrate.set_scarab_db_name name}
839
      prompt('Scarab database username', :default => 'root') {|username| ScarabMigrate.set_scarab_db_username username}
840
      prompt('Scarab database password') {|password| ScarabMigrate.set_scarab_db_password password}
841
    end
842
    prompt('Scarab database encoding', :default => 'Latin1') {|encoding| ScarabMigrate.encoding encoding}
843
    puts
844

  
845
    ScarabMigrate.migrate
846
  end
847
end