cloudsponge 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +4 -0
- data/Manifest.txt +15 -0
- data/README +70 -0
- data/Rakefile +44 -0
- data/TODO +3 -0
- data/lib/cloudsponge.rb +9 -0
- data/lib/cloudsponge/contact.rb +40 -0
- data/lib/cloudsponge/contact_importer.rb +176 -0
- data/lib/cloudsponge/cs_exception.rb +9 -0
- data/lib/cloudsponge/event.rb +33 -0
- data/lib/cloudsponge/utility.rb +82 -0
- data/test/test_contact.rb +22 -0
- data/test/test_contact_importer.rb +42 -0
- data/test/test_cs_exception.rb +7 -0
- data/test/test_utility.rb +11 -0
- metadata +78 -0
data/HISTORY
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
lib/cloudsponge.rb
|
6
|
+
lib/cloudsponge/contact.rb
|
7
|
+
lib/cloudsponge/contact_importer.rb
|
8
|
+
lib/cloudsponge/cs_exception.rb
|
9
|
+
lib/cloudsponge/event.rb
|
10
|
+
lib/cloudsponge/utility.rb
|
11
|
+
test/test_contact.rb
|
12
|
+
test/test_contact_importer.rb
|
13
|
+
test/test_cs_exception.rb
|
14
|
+
test/test_utility.rb
|
15
|
+
TODO
|
data/README
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
= cs_import
|
2
|
+
|
3
|
+
http://www.cloudsponge.com
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Spread the word with an email invite. Import contacts from Yahoo, Hotmail, MSN, Gmail, AOL, Outlook and Mac Address Book.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
=== Problem
|
12
|
+
Websites looking to grow their customer base usually turn to traditional, paid methods of advertising like search engine keywords, media buys, and generic email lists. Though these methods can be effective at times, they are no match for the testimonial power your very own customers can bring. By encouraging your customers to promote your site to their family and friends, you have an inexpensive advertising channel to acquire customers. If one customer refers their friends, and their friends refer their friends, and so on, and so on, you now have a viral site!
|
13
|
+
|
14
|
+
=== Solution
|
15
|
+
CloudSponge.com is THE tool you need to go viral! Here's how it works:
|
16
|
+
* Ask your customers to invite all their friends and family to your site.
|
17
|
+
* Use CloudSponge.com to pull your customer's contact list with their permission.
|
18
|
+
* Send an email invite to all the contacts provided by CloudSponge.com.
|
19
|
+
* Sit back and watch your customer base grow virally!
|
20
|
+
|
21
|
+
== SYNOPSIS:
|
22
|
+
|
23
|
+
Usage:
|
24
|
+
contacts = nil
|
25
|
+
importer = Cloudsponge::ContactImporter.new(DOMAIN_KEY, DOMAIN_PASSWORD)
|
26
|
+
resp = importer.begin_import('YAHOO')
|
27
|
+
puts "Navigate to #{resp[:consent_url]} and complete the authentication process."
|
28
|
+
loop do
|
29
|
+
events = importer.get_events
|
30
|
+
break unless events.select{ |e| e.is_error? }.empty?
|
31
|
+
unless events.select{ |e| e.is_complete? }.empty?
|
32
|
+
contacts = importer.get_contacts
|
33
|
+
break
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
== REQUIREMENTS:
|
38
|
+
|
39
|
+
JSON decoding package, currently supported are ActiveSupport::JSON and the JSON gem.
|
40
|
+
Neither of these are required, but if you don't have either on your system, a runtime
|
41
|
+
error will be generated.
|
42
|
+
|
43
|
+
== INSTALL:
|
44
|
+
|
45
|
+
sudo gem install cloudsponge
|
46
|
+
|
47
|
+
== LICENSE:
|
48
|
+
|
49
|
+
(The MIT License)
|
50
|
+
|
51
|
+
Copyright (c) 2010 Cloud Copy, Inc.
|
52
|
+
|
53
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
54
|
+
a copy of this software and associated documentation files (the
|
55
|
+
'Software'), to deal in the Software without restriction, including
|
56
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
57
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
58
|
+
permit persons to whom the Software is furnished to do so, subject to
|
59
|
+
the following conditions:
|
60
|
+
|
61
|
+
The above copyright notice and this permission notice shall be
|
62
|
+
included in all copies or substantial portions of the Software.
|
63
|
+
|
64
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
65
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
66
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
67
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
68
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
69
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
70
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
require 'lib/cloudsponge'
|
7
|
+
|
8
|
+
PKG_FILES = FileList["**/*"].exclude(/CVS|pkg|tmp|coverage|Makefile|\.nfs\./)
|
9
|
+
|
10
|
+
spec = Gem::Specification.new do |s|
|
11
|
+
s.name = 'cloudsponge'
|
12
|
+
s.version = Cloudsponge::VERSION
|
13
|
+
s.author = "Graeme Rouse"
|
14
|
+
s.email = "graeme@cloudsponge.com"
|
15
|
+
s.homepage = "http://www.cloudsponge.com"
|
16
|
+
s.platform = Gem::Platform::RUBY
|
17
|
+
s.summary = "A library wrapper for Cloudsponge.com's API"
|
18
|
+
s.description = <<-EOF
|
19
|
+
Usage:
|
20
|
+
contacts = nil
|
21
|
+
importer = Cloudsponge::ContactImporter.new(DOMAIN_KEY, DOMAIN_PASSWORD)
|
22
|
+
importer.begin_import('YAHOO')
|
23
|
+
loop do
|
24
|
+
events = importer.get_events
|
25
|
+
break unless events.select{ |e| e.is_error? }.empty?
|
26
|
+
unless events.select{ |e| e.is_completed? }.empty?
|
27
|
+
contacts = importer.get_contacts
|
28
|
+
break
|
29
|
+
end
|
30
|
+
end
|
31
|
+
EOF
|
32
|
+
|
33
|
+
#s.files = FileList["{test,lib}/**/*"].exclude("rdoc").to_a
|
34
|
+
s.files = PKG_FILES
|
35
|
+
# s.files = PKG_FILES
|
36
|
+
s.require_path = "lib"
|
37
|
+
s.has_rdoc = true
|
38
|
+
s.extra_rdoc_files = ["README", "HISTORY", "TODO"]
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
43
|
+
pkg.need_tar = true
|
44
|
+
end
|
data/TODO
ADDED
data/lib/cloudsponge.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/cloudsponge/contact_importer')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/cloudsponge/contact')
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/cloudsponge/event')
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/cloudsponge/cs_exception')
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + '/cloudsponge/utility')
|
6
|
+
|
7
|
+
module Cloudsponge
|
8
|
+
VERSION = '0.9.3'
|
9
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Cloudsponge
|
2
|
+
|
3
|
+
class Contact
|
4
|
+
attr_accessor :first_name, :last_name, :emails, :phones
|
5
|
+
|
6
|
+
def self.from_array(list)
|
7
|
+
list.map { |contact_data| Contact.new(contact_data) }.compact
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(contact_data)
|
11
|
+
# get the basic data
|
12
|
+
self.first_name = contact_data['first_name']
|
13
|
+
self.last_name = contact_data['last_name']
|
14
|
+
# get the phone numbers
|
15
|
+
self.phones = []
|
16
|
+
contact_data['phone'] && contact_data['phone'].each do |phone|
|
17
|
+
self.add_array_value(self.phones, phone['number'], phone['type'])
|
18
|
+
end
|
19
|
+
self.emails = []
|
20
|
+
contact_data['email'] && contact_data['email'].each do |email|
|
21
|
+
self.add_array_value(self.emails, email['address'], email['type'])
|
22
|
+
end
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def name
|
27
|
+
"#{self.first_name} #{self.last_name}"
|
28
|
+
end
|
29
|
+
def email
|
30
|
+
self.emails && self.emails.first && self.emails.first[:value]
|
31
|
+
end
|
32
|
+
def phone
|
33
|
+
self.phones && self.phones.first && self.phones.first[:value]
|
34
|
+
end
|
35
|
+
def add_array_value(collection, value, type = nil)
|
36
|
+
collection << {:value => value, :type => type}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# CloudSponge.com Ruby Library
|
2
|
+
# http://www.cloudsponge.com
|
3
|
+
# Copyright (c) 2010 Cloud Copy, Inc.
|
4
|
+
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
|
5
|
+
#
|
6
|
+
# Written by Graeme Rouse
|
7
|
+
# graeme@cloudsponge.com
|
8
|
+
|
9
|
+
module Cloudsponge
|
10
|
+
# Constants
|
11
|
+
URL_BASE = "https://api.cloudsponge.com/"
|
12
|
+
BEGIN_PATH = "begin_import/"
|
13
|
+
CONSENT_PATH = "user_consent/"
|
14
|
+
IMPORT_PATH = "import/"
|
15
|
+
APPLET_PATH = "desktop_applet/"
|
16
|
+
EVENTS_PATH = "events/"
|
17
|
+
CONTACTS_PATH = "contacts/"
|
18
|
+
|
19
|
+
class ContactImporter
|
20
|
+
attr_accessor :key, :password, :import_id
|
21
|
+
|
22
|
+
def initialize(key = nil, password = nil)
|
23
|
+
@key, @password = [key, password]
|
24
|
+
end
|
25
|
+
|
26
|
+
# guesses the most appropriate invocation for begin_import_xxx()
|
27
|
+
# returns an array of possible objects
|
28
|
+
# [
|
29
|
+
# :import_id => <import_id>,
|
30
|
+
# :consent_url => nil | <consent_url>,
|
31
|
+
# :applet_tag => nil | <applet_tag>
|
32
|
+
# ]
|
33
|
+
def begin_import(source_name, username = nil, password = nil, user_id = '', redirect_url = nil)
|
34
|
+
id = nil
|
35
|
+
consent_url = nil
|
36
|
+
applet_tag = nil
|
37
|
+
|
38
|
+
# look at the given service and decide how which begin function to invoke.
|
39
|
+
unless username.nil? || username.empty?
|
40
|
+
resp = begin_import_username_password(source_name, username, password, user_id)
|
41
|
+
else
|
42
|
+
unless (source_name =~ /OUTLOOK/i || source_name =~ /ADDRESSBOOK/i).nil?
|
43
|
+
resp = begin_import_applet(source_name, user_id)
|
44
|
+
applet_tag = create_applet_tag(resp['id'], resp['url'])
|
45
|
+
else
|
46
|
+
resp = begin_import_consent(source_name, user_id, redirect_url)
|
47
|
+
consent_url = resp['url']
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
@import_id = resp['import_id']
|
52
|
+
|
53
|
+
{:import_id => resp['import_id'], :consent_url => consent_url, :applet_tag => applet_tag}
|
54
|
+
end
|
55
|
+
|
56
|
+
# returns an array of Cloudsponge::Events with any new event or nil if no new events are available
|
57
|
+
def get_events(import_id = nil)
|
58
|
+
import_id ||= @import_id
|
59
|
+
|
60
|
+
# call to CloudSponge.com for the latest event status and return it
|
61
|
+
# create the appropriate url to fetch the contacts
|
62
|
+
full_url = generate_poll_url(EVENTS_PATH, import_id)
|
63
|
+
|
64
|
+
# get the response from the server and decode it
|
65
|
+
resp = Utility.get_and_decode_response(full_url)
|
66
|
+
# interpret the result
|
67
|
+
Event.from_array(resp['events'])
|
68
|
+
end
|
69
|
+
|
70
|
+
# call to CloudSponge.com for the contacts,
|
71
|
+
# returns nil (not ready)
|
72
|
+
# or [an array of Contacts, the contacts_owner record]
|
73
|
+
def get_contacts(import_id = nil)
|
74
|
+
import_id ||= @import_id
|
75
|
+
contacts = nil
|
76
|
+
if resp = get_contacts_raw(import_id)
|
77
|
+
# decode the contacts for consumption
|
78
|
+
contacts = Contact.from_array(resp['contacts'])
|
79
|
+
contacts_owner = Contact.new(resp['contacts_owner']) rescue nil
|
80
|
+
end
|
81
|
+
[contacts, contacts_owner]
|
82
|
+
end
|
83
|
+
|
84
|
+
# call to CloudSponge.com for the contacts,
|
85
|
+
# returns nil (not ready)
|
86
|
+
# or a hashmap of contact data
|
87
|
+
def get_contacts_raw(import_id)
|
88
|
+
resp = nil
|
89
|
+
|
90
|
+
# get the response from the server and decode it
|
91
|
+
begin
|
92
|
+
resp = Utility.get_and_decode_response(generate_poll_url(CONTACTS_PATH, import_id))
|
93
|
+
rescue CsException => e
|
94
|
+
raise e unless e.code == 404
|
95
|
+
end
|
96
|
+
|
97
|
+
resp
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
# invokes the begin import action for the user consent process.
|
103
|
+
# returns the URL of the consent page that the user must use to sign in and grant consent
|
104
|
+
# throws an exception if an invalid service is invoked.
|
105
|
+
def begin_import_consent(source_name, user_id = nil, redirect_url = nil)
|
106
|
+
# we need to pass in all params to the call
|
107
|
+
params = {:service => source_name, :user_id => user_id, :redirect_url => redirect_url}.reject{ |k,v| v.nil? || v.empty? }
|
108
|
+
|
109
|
+
# get and decode the response into an associated array
|
110
|
+
# Throws an exception if there was a problem at the server
|
111
|
+
Utility.post_and_decode_response(full_url(CONSENT_PATH), authenticated_params(params))
|
112
|
+
end
|
113
|
+
|
114
|
+
# invokes the begin import action for the desktop applet import process.
|
115
|
+
# returns the URL of the applet that should be displayed to the user within the appropriate applet tag
|
116
|
+
# throws an exception if an invalid service is invoked.
|
117
|
+
def begin_import_applet(source_name, user_id = nil)
|
118
|
+
# we need to pass in all params to the call
|
119
|
+
params = {:service => source_name, :user_id => user_id}
|
120
|
+
|
121
|
+
# get and decode the response into an associated array
|
122
|
+
# Throws an exception if there was a problem at the server
|
123
|
+
Utility.post_and_decode_response(full_url(APPLET_PATH), authenticated_params(params))
|
124
|
+
end
|
125
|
+
|
126
|
+
# invokes the begin import action for the desktop applet import process.
|
127
|
+
# returns the URL of the applet that should be displayed to the user within the appropriate applet tag
|
128
|
+
# throws an exception if an invalid service is invoked.
|
129
|
+
def begin_import_username_password(source_name, username, password, user_id)
|
130
|
+
# we need to pass in all params to the call
|
131
|
+
params = {:service => source_name, :user_id => user_id, :username => username, :password => password}
|
132
|
+
|
133
|
+
# get and decode the response into an associated array
|
134
|
+
# Throws an exception if there was a problem at the server
|
135
|
+
Utility.post_and_decode_response(full_url(IMPORT_PATH), authenticated_params(params))
|
136
|
+
end
|
137
|
+
|
138
|
+
def full_url(path)
|
139
|
+
"#{URL_BASE}#{BEGIN_PATH}#{path}"
|
140
|
+
end
|
141
|
+
|
142
|
+
def authenticated_params(params = {})
|
143
|
+
# append domain_key, domain_password to params and serialze into a query string
|
144
|
+
params.merge({:domain_key => self.key, :domain_password => self.password})
|
145
|
+
end
|
146
|
+
|
147
|
+
def authenticated_query(params = {})
|
148
|
+
# append domain_key, domain_password to params and serialze into a query string
|
149
|
+
Utility.object_to_query(authenticated_params(params))
|
150
|
+
end
|
151
|
+
|
152
|
+
def create_applet_tag(id, url)
|
153
|
+
<<-EOS
|
154
|
+
<APPLET archive="#{url}" code="ContactsApplet" id="Contact_Importer" width="0" height="0">
|
155
|
+
<PARAM name="cookieValue" value="document.cookie"/>
|
156
|
+
<PARAM name="importId" value="#{id}"/>
|
157
|
+
Your browser does not support Java which is required for this utility to operate correctly.
|
158
|
+
</APPLET>
|
159
|
+
EOS
|
160
|
+
end
|
161
|
+
|
162
|
+
def generate_poll_url(path, import_id)
|
163
|
+
# get the query_string with authentication params and assemble the full url
|
164
|
+
"#{URL_BASE}#{path}#{import_id}?#{authenticated_query}"
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
|
172
|
+
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Cloudsponge
|
2
|
+
EVENT_TYPES = %w{ INITIALIZING GATHERING SUBMITTING COMPLETE ERROR}
|
3
|
+
EVENT_STATUSES = %w{ PENDING INPROGRESS COMPLETED ERROR }
|
4
|
+
|
5
|
+
class Event
|
6
|
+
attr_accessor :event_type, :status, :value, :description
|
7
|
+
|
8
|
+
def self.from_array(list)
|
9
|
+
list.map { |event_data| Event.new(event_data) }.compact
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(event_data)
|
13
|
+
# is it an error?
|
14
|
+
|
15
|
+
# get the basic data
|
16
|
+
self.event_type = event_data['event_type']
|
17
|
+
self.status = event_data['status']
|
18
|
+
self.value = event_data['value']
|
19
|
+
self.description = event_data['description']
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def is_error?
|
24
|
+
self.event_type == 'ERROR'
|
25
|
+
end
|
26
|
+
|
27
|
+
def is_complete?
|
28
|
+
self.event_type == 'COMPLETE' && self.status == 'COMPLETED'
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Cloudsponge
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
require "net/https"
|
5
|
+
require "uri"
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'json'
|
9
|
+
rescue
|
10
|
+
end
|
11
|
+
|
12
|
+
class Utility
|
13
|
+
|
14
|
+
def self.object_to_query(object)
|
15
|
+
return object unless object.is_a? Hash
|
16
|
+
object.map{ |k,v| "#{URI.encode(k.to_s)}=#{URI.encode(v.to_s)}" }.join('&')
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.post_and_decode_response(url, params)
|
20
|
+
# post the response
|
21
|
+
response = post_url(url, params)
|
22
|
+
if response.code_type == Net::HTTPOK
|
23
|
+
# decode the response into an asscoiative array
|
24
|
+
resp = decode_response(response.body, 'json')
|
25
|
+
raise CsException.new(resp['error']['message'], response['code']) if resp['error']
|
26
|
+
else
|
27
|
+
raise CsException.new(response.body, response.code)
|
28
|
+
end
|
29
|
+
resp
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.get_and_decode_response(full_url)
|
33
|
+
# get the response
|
34
|
+
response = get_url(full_url)
|
35
|
+
|
36
|
+
if response.code_type == Net::HTTPOK
|
37
|
+
# decode the response into an asscoiative array
|
38
|
+
resp = decode_response(response.body, 'json')
|
39
|
+
raise CsException.new(resp['error']['message'], response['code']) if resp['error']
|
40
|
+
else
|
41
|
+
raise CsException.new(response.body, response.code)
|
42
|
+
end
|
43
|
+
resp
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.decode_response(response, format = 'json')
|
47
|
+
# TODO: account for systems that use a different JSON parser. Look for json gem...
|
48
|
+
# TODO: implement alternate formats: XML
|
49
|
+
object = {'error' => {'message' => 'failed to parse data.', 'code' => 1}}
|
50
|
+
begin
|
51
|
+
object = ActiveSupport::JSON.decode(response)
|
52
|
+
rescue
|
53
|
+
begin
|
54
|
+
object = JSON.parse(response)
|
55
|
+
rescue
|
56
|
+
end
|
57
|
+
end
|
58
|
+
object
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.get_url(url)
|
62
|
+
url = URI.parse(url)
|
63
|
+
open_http(url).get("#{url.path}?#{url.query}")
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.post_url(url, params)
|
67
|
+
url = URI.parse(url)
|
68
|
+
open_http(url).post("#{url.path}","#{object_to_query(params)}")
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.open_http(url)
|
72
|
+
http = Net::HTTP.new(url.host, url.port)
|
73
|
+
# @csimport_http.read_timeout = @timeout || 30
|
74
|
+
if url.port == 443
|
75
|
+
http.use_ssl = true
|
76
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
77
|
+
end
|
78
|
+
http.start unless http.started?
|
79
|
+
http
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "cloudsponge"
|
3
|
+
|
4
|
+
class TestContact < Test::Unit::TestCase
|
5
|
+
def test_new_from_data
|
6
|
+
data = {'first_name' => 'John', 'last_name' => 'Smith', 'email' => nil, 'phone' => nil}
|
7
|
+
assert contact = Cloudsponge::Contact.new(data)
|
8
|
+
assert_equal data['first_name'], contact.first_name
|
9
|
+
assert_equal data['last_name'], contact.last_name
|
10
|
+
assert_equal "#{data['first_name']} #{data['last_name']}", contact.name
|
11
|
+
assert_equal nil, contact.email
|
12
|
+
assert_equal nil, contact.phone
|
13
|
+
|
14
|
+
data = {'first_name' => 'John', 'last_name' => 'Smith', 'email' => [{'address' => 'joe@example.com'}], 'phone' => [{'number' => '555-1234'}]}
|
15
|
+
assert contact = Cloudsponge::Contact.new(data)
|
16
|
+
assert_equal data['first_name'], contact.first_name
|
17
|
+
assert_equal data['last_name'], contact.last_name
|
18
|
+
assert_equal "#{data['first_name']} #{data['last_name']}", contact.name
|
19
|
+
assert_equal 'joe@example.com', contact.email
|
20
|
+
assert_equal '555-1234', contact.phone
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require File.dirname(__FILE__) + "/../lib/cloudsponge"
|
3
|
+
|
4
|
+
class TestContactImporter < Test::Unit::TestCase
|
5
|
+
def test_version_exists
|
6
|
+
assert Cloudsponge::VERSION
|
7
|
+
end
|
8
|
+
|
9
|
+
DOMAIN_KEY = "Your Domain Key"
|
10
|
+
DOMAIN_PASSWORD = "Your Domain Password"
|
11
|
+
|
12
|
+
def test_u_p_import
|
13
|
+
contacts = nil
|
14
|
+
importer = Cloudsponge::ContactImporter.new(DOMAIN_KEY, DOMAIN_PASSWORD)
|
15
|
+
importer.begin_import('AOL', 'username', 'password')
|
16
|
+
loop do
|
17
|
+
events = importer.get_events
|
18
|
+
break unless events.select{ |e| e.is_error? }.empty?
|
19
|
+
unless events.select{ |e| e.is_complete? }.empty?
|
20
|
+
contacts = importer.get_contacts
|
21
|
+
break
|
22
|
+
end
|
23
|
+
end
|
24
|
+
assert contacts
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_auth_import
|
28
|
+
contacts = nil
|
29
|
+
importer = Cloudsponge::ContactImporter.new(DOMAIN_KEY, DOMAIN_PASSWORD)
|
30
|
+
resp = importer.begin_import('YAHOO')
|
31
|
+
puts "Navigate to #{resp[:consent_url]} and complete the authentication process."
|
32
|
+
loop do
|
33
|
+
events = importer.get_events
|
34
|
+
break unless events.select{ |e| e.is_error? }.empty?
|
35
|
+
unless events.select{ |e| e.is_complete? }.empty?
|
36
|
+
contacts = importer.get_contacts
|
37
|
+
break
|
38
|
+
end
|
39
|
+
end
|
40
|
+
assert contacts
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
require "test/unit"
|
3
|
+
require "../lib/cloudsponge"
|
4
|
+
|
5
|
+
class TestUtility < Test::Unit::TestCase
|
6
|
+
def test_decode_response
|
7
|
+
require "json"
|
8
|
+
object = {'key1' => 'value1', 'key2' => 'value2', 'integer_key' => 5}
|
9
|
+
assert_equal object, Cloudsponge::Utility.decode_response(JSON.generate(object))
|
10
|
+
end
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cloudsponge
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 9
|
8
|
+
- 3
|
9
|
+
version: 0.9.3
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Graeme Rouse
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-04-20 00:00:00 -07:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: " Usage:\n contacts = nil\n importer = Cloudsponge::ContactImporter.new(DOMAIN_KEY, DOMAIN_PASSWORD)\n importer.begin_import('YAHOO')\n loop do\n events = importer.get_events\n break unless events.select{ |e| e.is_error? }.empty?\n unless events.select{ |e| e.is_completed? }.empty?\n contacts = importer.get_contacts\n break\n end\n end\n"
|
22
|
+
email: graeme@cloudsponge.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README
|
29
|
+
- HISTORY
|
30
|
+
- TODO
|
31
|
+
files:
|
32
|
+
- HISTORY
|
33
|
+
- lib/cloudsponge/contact.rb
|
34
|
+
- lib/cloudsponge/contact_importer.rb
|
35
|
+
- lib/cloudsponge/cs_exception.rb
|
36
|
+
- lib/cloudsponge/event.rb
|
37
|
+
- lib/cloudsponge/utility.rb
|
38
|
+
- lib/cloudsponge.rb
|
39
|
+
- Manifest.txt
|
40
|
+
- Rakefile
|
41
|
+
- README
|
42
|
+
- test/test_contact.rb
|
43
|
+
- test/test_contact_importer.rb
|
44
|
+
- test/test_cs_exception.rb
|
45
|
+
- test/test_utility.rb
|
46
|
+
- TODO
|
47
|
+
has_rdoc: true
|
48
|
+
homepage: http://www.cloudsponge.com
|
49
|
+
licenses: []
|
50
|
+
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 1.3.6
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: A library wrapper for Cloudsponge.com's API
|
77
|
+
test_files: []
|
78
|
+
|