fellowshipone-api 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +14 -0
  6. data/Gemfile.lock +64 -0
  7. data/README.rdoc +44 -0
  8. data/Rakefile +32 -0
  9. data/fellowshipone_api.gemspec +25 -0
  10. data/lib/api/api_object.rb +141 -0
  11. data/lib/api/communication.rb +59 -0
  12. data/lib/api/contribution.rb +97 -0
  13. data/lib/api/contribution_list.rb +57 -0
  14. data/lib/api/fund.rb +40 -0
  15. data/lib/api/fund_list.rb +53 -0
  16. data/lib/api/household.rb +50 -0
  17. data/lib/api/household_list.rb +78 -0
  18. data/lib/api/member_household_list.rb +73 -0
  19. data/lib/api/mergeable_household_list.rb +79 -0
  20. data/lib/api/mergeable_person_list.rb +110 -0
  21. data/lib/api/person.rb +169 -0
  22. data/lib/api/person_list.rb +85 -0
  23. data/lib/api/search.rb +55 -0
  24. data/lib/auto_load.rb +17 -0
  25. data/lib/common.rb +76 -0
  26. data/lib/exceptions.rb +5 -0
  27. data/lib/fellowship_one.rb +54 -0
  28. data/lib/oauth_monkey_patch.rb +13 -0
  29. data/lib/readers/api_reader.rb +34 -0
  30. data/lib/readers/communication_reader.rb +19 -0
  31. data/lib/readers/contribution_list_reader.rb +37 -0
  32. data/lib/readers/contribution_reader.rb +18 -0
  33. data/lib/readers/fund_list_reader.rb +13 -0
  34. data/lib/readers/fund_reader.rb +14 -0
  35. data/lib/readers/household_list_reader.rb +62 -0
  36. data/lib/readers/household_reader.rb +18 -0
  37. data/lib/readers/member_household_list_reader.rb +27 -0
  38. data/lib/readers/person_list_reader.rb +37 -0
  39. data/lib/readers/person_reader.rb +20 -0
  40. data/lib/writers/api_writer.rb +64 -0
  41. data/lib/writers/communication_writer.rb +27 -0
  42. data/lib/writers/contribution_writer.rb +28 -0
  43. data/lib/writers/household_writer.rb +30 -0
  44. data/lib/writers/person_writer.rb +64 -0
  45. data/spec/api/person_spec.rb +21 -0
  46. data/spec/functional/fellowship_one_spec.rb +17 -0
  47. data/spec/readers/api_reader_spec.rb +7 -0
  48. data/spec/spec_helper.rb +47 -0
  49. data/spec/vcr_setup.rb +5 -0
  50. data/spec/writers/api_writer_spec.rb +7 -0
  51. metadata +129 -0
data/lib/api/person.rb ADDED
@@ -0,0 +1,169 @@
1
+ module FellowshipOne
2
+
3
+ include Enumerable
4
+
5
+ PersonAddress = Struct.new(:is_primary?, :street, :street2, :city, :state, :postal_code)
6
+ PersonCommunication = Struct.new(:is_phone?, :is_mobile?, :is_email?, :type, :value, :preferred?)
7
+
8
+ class Person < ApiObject
9
+ attr_accessor :addresses,
10
+ :communications
11
+
12
+ f1_attr_accessor :id,
13
+ :uri,
14
+ :image_uri,
15
+ :old_id,
16
+ :i_code,
17
+ :household_id,
18
+ :old_household_id,
19
+ :title,
20
+ :salutation,
21
+ :prefix,
22
+ :first_name,
23
+ :last_name,
24
+ :suffix,
25
+ :middle_name,
26
+ :goes_by_name,
27
+ :former_name,
28
+ :gender,
29
+ :date_of_birth,
30
+ :marital_status,
31
+ :household_member_type,
32
+ :is_authorized,
33
+ :status,
34
+ :occupation,
35
+ :employer,
36
+ :school,
37
+ :denomination,
38
+ :former_church,
39
+ :bar_code,
40
+ :member_envelope_code,
41
+ :default_tag_comment,
42
+ :weblink,
43
+ :solicit,
44
+ :thank,
45
+ :first_record,
46
+ :last_match_date,
47
+ :created_date,
48
+ :last_updated_date
49
+
50
+ # Loads the user by the specified ID.
51
+ #
52
+ # @param person_id The ID of the person to load.
53
+ #
54
+ # Returns a new Person object.
55
+ def self.load_by_id(person_id)
56
+ reader = PersonReader.new(person_id)
57
+ self.new(reader)
58
+ rescue
59
+ nil
60
+ end
61
+
62
+
63
+ # Constructor.
64
+ #
65
+ # @param reader (optional) The object that has the data. This can be a PersonReader or Hash object.
66
+ # @param options (optional) Options for including more information.
67
+ def initialize(reader = nil, options = {})
68
+ @writer_object = PersonWriter
69
+ if reader.is_a?(PersonReader)
70
+ initialize_from_json_object(reader.load_feed['person'])
71
+ elsif reader.is_a?(Hash)
72
+ initialize_from_json_object(reader)
73
+ else # new empty
74
+ reader = PersonReader.new
75
+ initialize_from_json_object(reader.load_new['person'])
76
+ end
77
+ end
78
+
79
+
80
+ def is_head_of_household?
81
+ (!self.household_member_type.nil? and self.household_member_type['name'].downcase == 'head')
82
+ end
83
+
84
+
85
+ def family_role
86
+ begin
87
+ self.household_member_type['name']
88
+ rescue
89
+ 'Other'
90
+ end
91
+ end
92
+
93
+
94
+ def is_child?
95
+ begin
96
+ self.household_member_type['name'].downcase == 'child'
97
+ rescue
98
+ false
99
+ end
100
+ end
101
+
102
+
103
+ def addresses
104
+ return nil if @addresses.nil?
105
+ return @addresses_cache unless @addresses_cache.nil?
106
+
107
+ @addresses_cache = []
108
+ @addresses['address'].each do |addr|
109
+ @addresses_cache << PersonAddress.new(
110
+ addr['addressType']['name'].downcase == 'primary',
111
+ addr['address1'],
112
+ addr['address2'],
113
+ addr['city'],
114
+ addr['stProvince'],
115
+ addr['postalCode']
116
+ )
117
+ end
118
+ @addresses_cache
119
+ end
120
+
121
+ def email_addresses
122
+ self.communications.collect { |c| c[:is_email?] ? c[:value] : nil }.compact
123
+ end
124
+
125
+ def all_numbers
126
+ self.communications.collect { |c| (c[:is_phone?] or c[:is_mobile?]) ? c[:value] : nil }.compact
127
+ end
128
+
129
+ def phone_numbers
130
+ self.communications.collect { |c| c[:is_phone?] ? c[:value] : nil }.compact
131
+ end
132
+
133
+ def mobile_numbers
134
+ self.communications.collect { |c| c[:is_mobile?] ? c[:value] : nil }.compact
135
+ end
136
+
137
+ def communications
138
+ return nil if @communications.nil?
139
+ return @communications_cache unless @communications_cache.nil?
140
+
141
+ @communications_cache = []
142
+ @communications['communication'].each do |comm|
143
+ @communications_cache << PersonCommunication.new(
144
+ comm['communicationType']['name'].to_s.downcase.include?('phone'),
145
+ comm['communicationType']['name'].to_s.downcase.include?('mobile'),
146
+ comm['communicationType']['name'].to_s.downcase.include?('email'),
147
+ comm['communicationType']['name'],
148
+ comm['communicationValue'],
149
+ comm['preferred'].to_s.downcase == 'true'
150
+ )
151
+ end
152
+ @communications_cache
153
+ end
154
+
155
+
156
+ def _field_map
157
+ {:id => '@id',
158
+ :uri => '@uri',
159
+ :imageUri => '@imageURI',
160
+ :oldId => '@oldID',
161
+ :iCode => '@iCode',
162
+ :householdId => '@householdID',
163
+ :oldHouseholdId => '@oldHouseholdID'}
164
+ end
165
+
166
+
167
+ end
168
+
169
+ end
@@ -0,0 +1,85 @@
1
+ module FellowshipOne
2
+
3
+ class PersonList
4
+
5
+ include Enumerable
6
+
7
+ attr_reader :count, :page_number, :total_records, :additional_pages
8
+
9
+
10
+ # Constructor.
11
+ #
12
+ # @param options A hash of options for loading the list.
13
+ #
14
+ # Options:
15
+ # :page - (optional) The page number to get.
16
+ # :reader - (optional) The Reader to use to load the data.
17
+ def initialize(options)
18
+ #options[:page] ||= 1
19
+ reader = options[:reader] || FellowshipOne::PersonListReader.new(options)
20
+ @json_data = reader.load_feed
21
+
22
+ @count = @json_data['@count'].to_i
23
+ @page_number = @json_data['@pageNumber'].to_i
24
+ @total_records = @json_data['@totalRecords'].to_i
25
+ @additional_pages = @json_data['@additionalPages'].to_i
26
+ end
27
+
28
+
29
+ # All the people in the list.
30
+ #
31
+ # @return array of names (first last).
32
+ def all_names
33
+ return [] unless @json_data['person']
34
+ @json_data['person'].collect { |person| [person['firstName'], person['lastName']].join(' ') }
35
+ end
36
+
37
+ alias_method :names, :all_names
38
+
39
+
40
+ # Get the specified person.
41
+ #
42
+ # @param index The index of the person to get.
43
+ #
44
+ # @return [Person]
45
+ def [](index)
46
+ Person.new( @json_data['person'][index] ) if @json_data['person'] and @json_data['person'][index]
47
+ end
48
+
49
+
50
+ # This method is needed for Enumerable.
51
+ def each &block
52
+ @json_data['person'].each{ |person| yield( Person.new(person) )}
53
+ end
54
+
55
+ # Alias the count method
56
+ alias :size :count
57
+
58
+ # Checks if the list is empty.
59
+ #
60
+ # @return True on empty, false otherwise.
61
+ def empty?
62
+ #@json_data['person'].empty?
63
+ self.count == 0 ? true : false
64
+ end
65
+
66
+
67
+ # Get all the people ids in the list.
68
+ #
69
+ # @return An array of people ids.
70
+ def ids
71
+ (@json_data['person'].collect { |person| person['@id'] }).uniq
72
+ end
73
+
74
+
75
+ # Access to the raw JSON data. This method is needed for merging lists.
76
+ #
77
+ # @returns Raw JSON data.
78
+ def raw_data
79
+ @json_data
80
+ end
81
+
82
+ end
83
+
84
+
85
+ end
data/lib/api/search.rb ADDED
@@ -0,0 +1,55 @@
1
+ module FellowshipOne
2
+
3
+ class Search
4
+
5
+ def self.search_for_contributions_by_date(start_date, end_date, page=1, per_page=500)
6
+ options = {:start_date => start_date, :end_date => end_date, :page => page, :per_page => per_page}
7
+ reader = FellowshipOne::ContributionListReader.new(options)
8
+ ContributionList.new({:reader => reader})
9
+ end
10
+
11
+ def self.search_for_contributions_by_household_id(household_id, page=1, per_page=500)
12
+ options = {:household_id => household_id, :page => page, :per_page => per_page}
13
+ reader = FellowshipOne::ContributionListReader.new(options)
14
+ ContributionList.new({:reader => reader})
15
+ end
16
+
17
+ def self.search_for_contributions_by_individual_id(individual_id, page=1, per_page=500)
18
+ options = {:individual_id => individual_id, :page => page, :per_page => per_page}
19
+ reader = FellowshipOne::ContributionListReader.new(options)
20
+ ContributionList.new({:reader => reader})
21
+ end
22
+
23
+ def self.search_for_person_by_name(query, page=1)
24
+ options = {:page => page, :search_for => query}
25
+ reader = FellowshipOne::PersonListReader.new(options)
26
+ PersonList.new({:reader => reader})
27
+ end
28
+
29
+ def self.search_for_person_by_household_id(query, page=1)
30
+ options = {:page => page, :hsdid => query}
31
+ reader = FellowshipOne::PersonListReader.new(options)
32
+ PersonList.new({:reader => reader})
33
+ end
34
+
35
+ def self.search_for_person_by_communication(query, page=1)
36
+ options = {:page => page, :communication => query}
37
+ reader = FellowshipOne::PersonListReader.new(options)
38
+ PersonList.new({:reader => reader})
39
+ end
40
+
41
+ def self.search_for_person_created_on_or_after(created_date, page=1)
42
+ options = {:page => page, :created_date => created_date}
43
+ reader = FellowshipOne::PersonListReader.new(options)
44
+ PersonList.new({:reader => reader})
45
+ end
46
+
47
+ def self.search_for_household_by_name(name, page=1)
48
+ options = {:page => page, :search_for => name}
49
+ reader = FellowshipOne::HouseholdListReader.new(options)
50
+ HouseholdList.new({:reader => reader})
51
+ end
52
+
53
+ end
54
+
55
+ end
data/lib/auto_load.rb ADDED
@@ -0,0 +1,17 @@
1
+ module FellowshipOne
2
+
3
+ require FELLOWSHIPONE_LIB_DIR + '/exceptions.rb'
4
+
5
+ api_path = FELLOWSHIPONE_LIB_DIR + '/api/'
6
+ require api_path + 'api_object.rb'
7
+ Dir["#{api_path}/*.rb"].each { |f| require(f) }
8
+
9
+ readers_path = FELLOWSHIPONE_LIB_DIR + '/readers/'
10
+ require readers_path + 'api_reader.rb'
11
+ Dir["#{readers_path}/*.rb"].each { |f| require(f) }
12
+
13
+ writers_path = FELLOWSHIPONE_LIB_DIR + '/writers/'
14
+ require writers_path + 'api_writer.rb'
15
+ Dir["#{writers_path}/*.rb"].each { |f| require(f) }
16
+
17
+ end
data/lib/common.rb ADDED
@@ -0,0 +1,76 @@
1
+ module FellowshipOne
2
+ require 'json'
3
+ require 'time'
4
+
5
+ def self.api_request(method, path, params = {}, body = '')
6
+ # response = case method
7
+ # when :post
8
+ # Typhoeus::Request.post(url, {:headers => self._build_api_headers, :body => body})
9
+ # when :get
10
+ # Typhoeus::Request.get(url, {:headers => self._build_api_headers, :params => params})
11
+ # when :put
12
+ # Typhoeus::Request.put(url, {:headers => self._build_api_headers, :body => body})
13
+ # when :delete
14
+ # Typhoeus::Request.delete(url, {:headers => self._build_api_headers, :params => params})
15
+ # end
16
+
17
+ response = self._oauth_request_get(method, path, params, body)
18
+
19
+ unless response.success?
20
+ puts response.inspect
21
+ if response.code > 0
22
+ raise FellowshipOneExceptions::UnableToConnectToFellowshipOne.new(response.body)
23
+ else
24
+ begin
25
+ error_messages = JSON.parse(response.body)['error_message']
26
+ rescue
27
+ response_code_desc = response.headers.partition("\r\n")[0].sub(/^\S+/, '') rescue nil
28
+ raise FellowshipOneExceptions::UnknownErrorConnectingToFellowshipOne.new("Unknown error when connecting to FellowshipOne API. #{response_code_desc}")
29
+ else
30
+ raise FellowshipOneExceptions::FellowshipOneResponseError.new(error_messages)
31
+ end
32
+ end
33
+ end
34
+
35
+ response
36
+ end
37
+
38
+
39
+ def self._oauth_request_get(method, path, params, body)
40
+ consumer_env = FellowshipOne::Api.is_production ? '' : '.staging'
41
+ base_url = "https://#{FellowshipOne::Api.church_code}#{consumer_env}.fellowshiponeapi.com"
42
+ url = base_url + path
43
+ if method == :get
44
+ url_params = params.collect { |k, v| "#{k}=#{CGI::escape(v.to_s)}" }.join('&')
45
+ url_params = nil if url_params.empty?
46
+ url = [url, url_params].compact.join('?')
47
+ params = {}
48
+ end
49
+
50
+ consumer = OAuth::Consumer.new(FellowshipOne::Api.consumer_key,
51
+ FellowshipOne::Api.consumer_secret,
52
+ :site => base_url,
53
+ :http_method => method)
54
+ access_token = OAuth::AccessToken.new(consumer, FellowshipOne::Api.api_token, FellowshipOne::Api.api_secret)
55
+
56
+ options = {:params => params, :method => method, :body => body}
57
+ oauth_params = {:consumer => consumer, :token => access_token}
58
+ hydra = Typhoeus::Hydra.new
59
+ req = Typhoeus::Request.new(url, options)
60
+
61
+ # {'Content-Type' => 'application/vnd.fellowshiponeapi.com.people.people.v2+json'}
62
+ # req.headers.merge!({'Content-Type' => 'application/json'})
63
+ req.options[:headers].merge!({'Content-Type' => 'application/json'})
64
+ oauth_helper = OAuth::Client::Helper.new(req, oauth_params.merge(:request_uri => url))
65
+
66
+ #req.headers.merge!({"Authorization" => oauth_helper.header})
67
+ req.options[:headers].merge!({"Authorization" => oauth_helper.header}) # Signs the request
68
+
69
+ hydra.queue(req)
70
+ hydra.run
71
+
72
+ req.response
73
+ end
74
+
75
+ end
76
+
data/lib/exceptions.rb ADDED
@@ -0,0 +1,5 @@
1
+ module FellowshipOneExceptions
2
+ class UnableToConnectToFellowshipOne < StandardError; end
3
+ class UnknownErrorConnectingToFellowshipOne < StandardError; end
4
+ class FellowshipOneResponseError < StandardError; end
5
+ end
@@ -0,0 +1,54 @@
1
+ require 'oauth'
2
+ require 'yaml'
3
+ require 'typhoeus'
4
+ require 'oauth/request_proxy/typhoeus_request'
5
+ require 'json'
6
+
7
+ # The path to the lib directory.
8
+ FELLOWSHIPONE_LIB_DIR = File.dirname(__FILE__)
9
+
10
+ require File.dirname(__FILE__) + '/auto_load.rb'
11
+
12
+ require File.dirname(__FILE__) + '/common.rb'
13
+
14
+ require File.dirname(__FILE__) + '/oauth_monkey_patch'
15
+
16
+ module FellowshipOne
17
+
18
+ class Api
19
+
20
+ class << self
21
+ attr_reader :church_code, :consumer_key, :consumer_secret, :api_token, :api_secret, :is_production
22
+ end
23
+
24
+ def self.establish_connection(church_code, consumer_key, consumer_secret, callback_url, production = true)
25
+ if church_code.nil? or consumer_key.nil? or consumer_secret.nil?
26
+ raise FellowshipOneExceptions::UnableToConnectToFellowshipOne.new('Church code, Consumer Key and Consumer Secret cannot be nil.')
27
+ end
28
+
29
+ consumer_env = production ? '' : '.staging' # Yes, blank is production
30
+
31
+ puts "F1 URL: https://#{church_code}#{consumer_env}.fellowshiponeapi.com"
32
+
33
+ consumer = OAuth::Consumer.new(consumer_key, consumer_secret,
34
+ :site => "https://#{church_code}#{consumer_env}.fellowshiponeapi.com",
35
+ :request_token_path => '/v1/Tokens/RequestToken',
36
+ :authorize_path => '/v1/PortalUser/Login',
37
+ :access_token_path => '/v1/Tokens/AccessToken')
38
+
39
+ consumer.get_request_token(:oauth_callback => callback_url)
40
+ end
41
+
42
+ def self.connect(church_code, consumer_key, consumer_secret, oauth_token, oauth_secret, production = true)
43
+ raise FellowshipOneExceptions::UnableToConnectToFellowshipOne.new('Church Code, Token and Secret cannot be nil.') if oauth_token.nil? or oauth_secret.nil?
44
+ @church_code = church_code
45
+ @consumer_key = consumer_key
46
+ @consumer_secret = consumer_secret
47
+ @api_token = oauth_token
48
+ @api_secret = oauth_secret
49
+ @is_production = production
50
+ end
51
+
52
+ end
53
+
54
+ end