seven1m / onebody

OneBody is free, open-source, web-based social networking and online directory software for churches.

onebody / script / sync
100644 108 lines (88 sloc) 3.552 kb
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
#!/usr/bin/env ruby
 
# usage:
# sync [options] CONNECTOR [connector_args]
 
# examples:
# script/sync csv /path/to/people.csv /path/to/families.csv
# script/sync coms /path/to/comsdata
 
# multisite example:
# script/sync -s "Site 1" csv /path/to/people.csv /path/to/families.csv
 
MAX_ERRORS = 10
 
require 'optparse'
options = {}
parser = OptionParser.new do |opts|
  connectors = Dir[File.join(File.dirname(__FILE__), '../lib/connectors/*.rb')].to_a.map { |f| File.split(f).last.split('.').first }.select { |c| !%w(base test example).include? c }
  opts.banner = "Usage: script/sync [options] CONNECTOR [connector_args]\nAvailable Connectors: #{connectors.join(', ')}"
  opts.on("-s", '--site "Site Name"', "specify site name (if multisite enabled)") do |val|
    options[:site] = val
  end
  opts.on("-e", '--environment production', "specify environment (development, production)") do |val|
    options[:environment] = val
  end
end
parser.parse!
 
unless connector_name = ARGV[0]
  puts parser.help
  exit
end
args = ARGV[1..-1]
 
RAILS_ENV = options[:environment]
 
require File.dirname(__FILE__) + '/../config/environment'
require RAILS_ROOT + "/lib/connectors/#{connector_name}"
 
logger = RAILS_DEFAULT_LOGGER
 
logger.info "Initializing Sync..."
connector = eval(connector_name.capitalize+'Connector').new(*args)
 
unless last_update = Date.parse(ActiveRecord::Base.connection.select_one("SELECT last_update FROM sync_info")['last_update']).to_time rescue nil
  ActiveRecord::Base.connection.delete("DELETE FROM sync_info")
  ActiveRecord::Base.connection.insert("INSERT INTO sync_info (last_update) values (NULL)")
  last_update = Date.new(1970, 1, 1).to_time
end
 
update_time = Time.now.strftime '%Y-%m-%d %H:%M'
 
error_count = 0
 
if Setting.get(:features, :multisite)
  Site.current = Site.find_by_name(options[:site])
else
  Site.current = Site.find(1)
end
 
logger.info "Syncing people data..."
connector.each_person(last_update) do |person|
  begin
    p = Person.find_by_legacy_id(person[:legacy_id]) || Person.new(:legacy_id => person[:legacy_id])
    if p.email_changed?
      if person[:email] != p.email
        person.delete(:email)
      else
        person[:email_changed] = false
      end
    end
    [:mobile_phone, :work_phone, :fax].each { |a| person[a] = person[a] ? person[a].to_s.scan(/\d/).join('').to_i : nil }
    p.update_attributes!(person)
  rescue => e
    logger.error e
    error_count += 1
    if error_count > MAX_ERRORS
      raise "Too many errors. Check the log. Last error was:\n#{e}"
    end
  end
end
 
logger.info "Syncing family data..."
connector.each_family(last_update) do |family|
  begin
    f = Family.find_by_legacy_id(family[:legacy_id]) || Family.new(:legacy_id => family[:legacy_id])
    family[:home_phone] = family[:home_phone] ? family[:home_phone].to_s.scan(/\d/).join('').to_i : nil
    f.update_attributes!(family)
    Person.update_all "family_id = #{f.id}", "legacy_family_id = #{f.legacy_id}"
  rescue => e
    logger.error e
    error_count += 1
    if error_count > MAX_ERRORS
      raise "Too many errors. Check the log. Last error was:\n#{e}"
    end
  end
end
 
logger.info "Purging data..."
Person.destroy_all "legacy_id not in (#{connector.people_ids.join(',')})"
Family.destroy_all "legacy_id not in (#{connector.family_ids.join(',')})"
Person.destroy_all "(select count(*) from families where id=people.family_id) = 0"
 
logger.info "Recording update details..."
ActiveRecord::Base.connection.update("UPDATE sync_info SET last_update = '#{update_time}'")
 
logger.info "Finished Sync."