This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def import | |
parse_card | |
if found_contact | |
update_contact | |
else | |
create_contact | |
end | |
process_associations | |
end | |
def parse_card | |
card = Vpim::Vcard.decode(self.data).first | |
@card = {} | |
@card[:first_name] = card.name.given.capitalize unless card.name.given.blank? | |
@card[:last_name] = card.name.family.capitalize unless card.name.family.blank? | |
# if there is no first or last name, try getting it from the full name attribute | |
if !@card[:first_name] && !@card[:last_name] | |
@card[:first_name], @card[:last_name] = card.name.fullname.split.map(&:capitalize) unless card.name.fullname.blank? | |
end | |
@card[:birthday] = card.birthday unless card.birthday.blank? | |
@card[:url] = card.url.uri unless card.url.blank? | |
@card[:notes] = card.note unless card.note.blank? | |
@card[:photo] = card.photos.first unless card.photos.size.zero? | |
# phone is something like: #<Vpim::Vcard::Telephone: "123-456-7890", pref, work | |
# doing phone.to_s will extract just the number | |
@card[:phones] = card.telephones.map {|p| {:label => get_label(p), :number => p.to_s.downcase}} | |
# email is something like: #<Vpim::Vcard::Email: "test@yahoo.com", pref, home | |
# doing email.to_s will extract just the email address | |
@card[:emails] = card.emails.map {|e| {:label => get_label(e), :address => e.to_s.downcase}} | |
# set default country | |
@usa_id = Country.find_by_name("United States") | |
@card[:addresses] = card.addresses.map do |a| | |
country_id = get_country(a) | |
{:label => get_label(a), | |
:country_id => country_id, | |
:region_id => get_region(a, country_id), | |
:street_1 => a.street, | |
:street_2 => a.pobox, | |
:city => a.locality, | |
:postal_code => a.postalcode | |
} | |
end | |
filter_card_data(@card) | |
end | |
def filter_card_data(card_data) | |
# remove newlines and backslashes from text. | |
# {x=>"foo\n", y=>[{z=>"bar\\"}]} => {x=>"foo", y=>[{z=>"bar"}]} | |
card_data.each do |k, v| | |
if card_data[k].is_a?(Array) | |
card_data[k].each do |arr| | |
filter_card_data(arr) | |
end | |
else | |
next if skip_list.include?(k) | |
card_data[k] = remove_newlines(v).gsub("\\", "") | |
end | |
end | |
end | |
def skip_list | |
[:photo, :birthday] | |
end | |
def remove_newlines(text) | |
text.to_s.gsub("\n", "") | |
end | |
def get_country(card_address) | |
return @usa_id if card_address.country.blank? | |
# u.s.a. -> usa | |
card_country = card_address.country.gsub(".", "") | |
@countries ||= Country.all | |
country_attributes = [:name, :official_name, :alpha_2_code, :alpha_3_code] | |
find_in_list(@countries, country_attributes, card_country) || @usa_id | |
end | |
def get_region(card_address, country_id = @usa_id) | |
return if card_address.region.blank? | |
# nev. --> nev | |
card_region = card_address.region.split(/^(.*)?\.+$/).last | |
regions_for_country = Region.find_all_by_country_id(country_id) | |
region_attributes = [:name, :abbreviation, :abbrev2, :abbrev3] | |
find_in_list(regions_for_country, region_attributes, card_region) | |
end | |
def find_in_list(records, attributes, to_find) | |
# a better way of doing Country.all.find {|c| [c.name, c.official_name].compact.map(&:downcase).include?(to_find.downcase) } | |
records.find {|r| attributes.map{|a| r.send(a)}.compact.map(&:downcase).include?(to_find.downcase) } if records | |
end | |
def update_contact | |
@contact.update_attributes(contact_attributes) | |
end | |
def contact_attributes | |
{:url => @card[:url], | |
:notes => @card[:notes], | |
:birthday => @card[:birthday]} | |
end | |
def found_contact | |
[find_by_emails, find_by_phones, find_by_addresses].each do |method| | |
if contact_found = method | |
return @contact = contact_found | |
end | |
end | |
# not found | |
nil | |
end | |
def find_by_emails | |
emails = @card[:emails].map {|e| e[:address]} | |
email = Email.find_by_address(emails) | |
email.contact if email | |
end | |
def find_by_phones | |
phones = @card[:phones].map {|p| p[:number]} | |
phone = Phone.find_by_number(phones) | |
phone.contact if phone | |
end | |
def find_by_addresses | |
streets = @card[:addresses].map {|a| a[:street_1]} | |
address = Address.find_by_street_1(streets) | |
address.contact if address | |
end | |
def create_contact | |
@contact = Contact.create(contact_attributes.merge(:first_name => @card[:first_name], | |
:last_name => @card[:last_name])) | |
end | |
def process_associations | |
card_emails | |
card_phones | |
card_addresses | |
# only replace a contact's photo if they don't have one set | |
card_photo if @card[:photo] && @contact.photo.nil? | |
end | |
def card_addresses | |
streets = @contact.addresses.map(&:street_1) | |
addresses = @card[:addresses].reject {|a| a[:region_id].nil? || streets.include?(a[:street_1])} | |
addresses.each do |address| | |
@contact.addresses << Address.create(address) | |
end | |
end | |
def card_phones | |
contact_numbers = @contact.phones.map(&:number).map(&:numbers_only) | |
phones = @card[:phones].reject {|p| contact_numbers.include?(p[:number].numbers_only) } | |
phones.each do |phone| | |
@contact.phones << Phone.create(phone) | |
end | |
end | |
def card_emails | |
contact_emails = @contact.emails.map(&:address) | |
emails = @card[:emails].reject {|e| contact_emails.include?(e[:address]) } | |
emails.each do |email| | |
@contact.emails << Email.create(email) | |
end | |
end | |
def card_photo | |
photo_album = PhotoAlbum.find_or_create_by_name_with_access_level('users', 'admin') | |
access_level = AccessLevel.find_by_name('public') | |
@contact.photo = Photo.create(:image_file_string => @card[:photo], | |
:contact_id => @contact.id, | |
:name => "#{@contact.first_name} #{@contact.last_name}".strip, | |
:description => "User photo", | |
:access_level_id => access_level.id, | |
:photo_album_id => photo_album.id, | |
:server_format => "JPEG") | |
end | |
def get_label(obj) | |
obj.location.blank? ? nil : remove_newlines(obj.location).gsub("-","").strip | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'spec_helper' | |
describe Vcard do | |
def reset_tables | |
Vcard.delete_all | |
Contact.all.map(&:destroy) | |
end | |
def country_mock | |
@usa = mock_model(Country, {:name => 'United States'}) | |
Country.stub!(:find_by_name).with('United States').and_return(@usa) | |
end | |
def setup_contact | |
@contact = Contact.create!(:first_name => 'test', :last_name => 'test') | |
end | |
def get_card_data(card) | |
card_data = File.read(RAILS_ROOT + "/spec/fixtures/vcard/#{card}.vcf") | |
@vcard = Vcard.create!(:data => card_data) | |
end | |
def add_email(address) | |
email = Email.create!(:address => address) | |
@contact.emails << email | |
end | |
def add_address(street) | |
address = Address.create!(:street_1 => street) | |
@contact.addresses << address | |
end | |
def add_phone(number) | |
phone = Phone.create!(:number => number) | |
@contact.phones << phone | |
end | |
before(:all) do | |
reset_tables | |
country_mock | |
setup_contact | |
end | |
describe "vCard parsing tests" do | |
before(:all) do | |
get_card_data(:test) | |
@vcard.parse_card | |
end | |
context "finding a contact" do | |
it "should find the contact when an email for the contact exists" do | |
add_email("test@test.com") | |
end | |
it "should find the contact when a phone for the contact exists" do | |
add_phone("000-000-0000") | |
end | |
it "should find the contact when an address for the contact exists" do | |
add_address("123 test st.") | |
end | |
after(:each) do | |
@vcard.found_contact.should == @contact | |
end | |
end | |
context "sanitizing data" do | |
it "should remove all new lines and double backslashes from nested card data" do | |
test_data = {1=>"foo\n", 2=>[{3=>"bar\\"}]} | |
@vcard.filter_card_data(test_data).should == {1=>"foo", 2=>[{3=>"bar"}]} | |
end | |
end | |
context "finding the location" do | |
it "should default to United States if no country is provided" do | |
address = mock_model(Address) | |
address.stub(:country) | |
@vcard.get_country(address).should == @usa | |
end | |
end | |
end | |
describe "vcard importing tests" do | |
context "updating a contact" do | |
it "should update the attributes of a pre-existing contact" do | |
add_email("test@test.com") | |
get_card_data(:test) | |
@vcard.import | |
@contact.reload | |
@contact.notes.should_not be_nil | |
@contact.birthday.should_not be_nil | |
@contact.url.should_not be_nil | |
end | |
it "should add multiple emails to a pre-existing contact but not add one if it already exists" do | |
@contact = Contact.create(:first_name => 'James', :last_name => 'Kirk') | |
add_email("kirk@enterprise.com") | |
get_card_data(:kirk) | |
@vcard.import | |
@contact.emails.length.should == 3 | |
end | |
it "should add multiple phones to a pre-existing contact but not add one if it already exists" do | |
@contact = Contact.create(:first_name => 'James', :last_name => 'Kirk') | |
add_phone("123-123-1234") | |
get_card_data(:kirk) | |
@vcard.import | |
@contact.phones.length.should == 3 | |
end | |
it "should add multiple addresses to a pre-existing contact but not add one if it already exists" do | |
@contact = Contact.create(:first_name => 'James', :last_name => 'Kirk') | |
add_address("1000 space drive") | |
get_card_data(:kirk) | |
@vcard.import | |
@contact.addresses.length.should == 3 | |
end | |
end | |
context "creating a contact" do | |
before(:each) do | |
Contact.all.map(&:destroy) | |
end | |
it "should create a contact when it cannot be found by email, phone, or address" do | |
get_card_data(:test) | |
@vcard.import | |
Contact.count.should == 1 | |
end | |
it "should create a new contact and add multiple addresses" do | |
get_card_data(:kirk) | |
@vcard.import | |
Contact.find_by_first_name_and_last_name("James", "Kirk").addresses.length.should == 3 | |
end | |
it "should create a new contact and add multiple emails" do | |
get_card_data(:kirk) | |
@vcard.import | |
Contact.find_by_first_name_and_last_name("James", "Kirk").emails.length.should == 3 | |
end | |
it "should create a new contact and add multiple phones" do | |
get_card_data(:kirk) | |
@vcard.import | |
Contact.find_by_first_name_and_last_name("James", "Kirk").phones.length.should == 3 | |
end | |
it "should create a photo for the contact" do | |
get_card_data(:felds) | |
access_level = mock_model(AccessLevel, {:name => "public"}) | |
AccessLevel.should_receive(:find_by_name).with('public').and_return(access_level) | |
photo_album = mock_model(PhotoAlbum, {:name => "some photo album"}) | |
PhotoAlbum.should_receive(:find_or_create_by_name_with_access_level).and_return(photo_album) | |
Photo.should_receive(:create).and_return(Photo.new) | |
@vcard.import | |
Contact.find_by_first_name_and_last_name("Lawrence", "Felds").photo.should_not be_nil | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment