relateiq_client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,77 @@
1
+ module RelateIq
2
+ class List
3
+ attr_accessor :id,
4
+ :title,
5
+ :list_type,
6
+ :modified_date,
7
+ :fields
8
+
9
+ def initialize(attrs = {})
10
+ if attrs.key? :listType
11
+ initialize_from_api(attrs)
12
+ else
13
+ initialize_from_user(attrs)
14
+ end
15
+ end
16
+
17
+ def self.resource
18
+ @resource ||= ServiceFactory.get_endpoint('lists')
19
+ end
20
+
21
+ def self.all
22
+ @all ||= from_json(resource.get)
23
+ end
24
+
25
+ def self.find_by_title(title)
26
+ all.find { |l| l.title.downcase == title.downcase }
27
+ end
28
+
29
+ def self.find(id)
30
+ all.find { |l| l.id == id }
31
+ end
32
+
33
+ def self.clean_cache
34
+ @all = nil
35
+ end
36
+
37
+ def self.from_json(json_string)
38
+ lists_hash = JSON.parse(json_string, symbolize_names: true)
39
+ if lists_hash.key? :objects
40
+ lists_hash[:objects].map { |li| List.new(li) }
41
+ else
42
+ List.new(lists_hash)
43
+ end
44
+ end
45
+
46
+ def upsert_item(list_item_hash)
47
+ list_item_hash.merge!(list_id: id)
48
+ list_item_class.new(list_item_hash).save
49
+ end
50
+
51
+ def items_by_contact_id(contact_id)
52
+ list_item_class.find_by_contact(id, contact_id)
53
+ end
54
+
55
+ private
56
+
57
+ def list_item_class
58
+ @list_item_class ||= ListItem
59
+ end
60
+
61
+ def initialize_from_api(attrs)
62
+ @id = attrs.fetch(:id)
63
+ @title = attrs.fetch(:title)
64
+ @fields = attrs.fetch(:fields)
65
+ @list_type = attrs.fetch(:listType)
66
+ @modified_date = attrs.fetch(:modifiedDate)
67
+ end
68
+
69
+ def initialize_from_user(attrs)
70
+ @id = attrs.fetch(:id, nil)
71
+ @title = attrs.fetch(:title, nil)
72
+ @list_type = attrs.fetch(:list_type, nil)
73
+ @modified_date = attrs.fetch(:modified_date, nil)
74
+ @fields = attrs.fetch(:fields, nil)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,107 @@
1
+ module RelateIq
2
+ class ListItem
3
+ attr_accessor :list_id,
4
+ :id,
5
+ :name,
6
+ :account_id,
7
+ :contact_ids,
8
+ :field_values
9
+
10
+ # field values always contains decoded values
11
+ # for example { 'Status' => 'Application Submitted' }
12
+
13
+ def initialize(attrs = {})
14
+ if attrs.key? :listId
15
+ initialize_from_api(attrs)
16
+ else
17
+ initialize_by_user(attrs)
18
+ end
19
+ end
20
+
21
+ def initialize_by_user(attrs)
22
+ @list_id = attrs.fetch(:list_id)
23
+ @id = attrs.fetch(:id, nil)
24
+ @name = attrs.fetch(:name, nil)
25
+ @account_id = attrs.fetch(:account_id, nil)
26
+ @contact_ids = attrs.fetch(:contact_ids, [])
27
+ @field_values = attrs.fetch(:field_values, [])
28
+ end
29
+
30
+ def initialize_from_api(attrs)
31
+ @list_id = attrs.fetch(:listId)
32
+ @id = attrs.fetch(:id, nil)
33
+ @name = attrs.fetch(:name, nil)
34
+ @account_id = attrs.fetch(:accountId, nil)
35
+ @contact_ids = attrs.fetch(:contactIds, [])
36
+ @field_values = decode_field_values(attrs.fetch(:fieldValues, nil))
37
+ end
38
+
39
+ def self.resource(list_id)
40
+ @resource ||= ServiceFactory.get_endpoint('lists')
41
+ @resource["#{list_id}/listitems"]
42
+ end
43
+
44
+ def self.from_json(json_string)
45
+ list_item_hash = JSON.parse(json_string, symbolize_names: true)
46
+ if list_item_hash.key? :objects
47
+ list_item_hash[:objects].map { |li| ListItem.new(li) }
48
+ else
49
+ ListItem.new(list_item_hash)
50
+ end
51
+ end
52
+
53
+ def self.create(attrs)
54
+ ListItem.new(attrs).save
55
+ end
56
+
57
+ def self.find_by_contact(list_id, contact_id)
58
+ from_json(resource(list_id)["?contactIds=#{contact_id}"].get)
59
+ end
60
+
61
+ def save
62
+ if id
63
+ ListItem.from_json(ListItem.resource(list_id)["#{id}"].put to_json)
64
+ else
65
+ ListItem.from_json(ListItem.resource(list_id).post to_json)
66
+ end
67
+ end
68
+
69
+ def to_json
70
+ to_hash.to_json
71
+ end
72
+
73
+ private
74
+
75
+ def to_hash
76
+ result = { 'listId' => list_id }
77
+ result.merge!('id' => id) if id
78
+ result.merge!('name' => name) if name
79
+ result.merge!('accountId' => account_id) if account_id && list.list_type == 'account'
80
+ result.merge!('contactIds' => contact_ids) if contact_ids && contact_ids.count > 0
81
+ result.merge!('fieldValues' => encode_field_values(field_values)) if field_values && field_values.count > 0
82
+ result
83
+ end
84
+
85
+ def encode_field_values(values)
86
+ return [] unless values
87
+ encoder = field_value_encoder.new(list: list)
88
+ encoded_values = {}
89
+ values.each { |fv| encoded_values.merge!(encoder.encode(fv)) }
90
+ encoded_values
91
+ end
92
+
93
+ def decode_field_values(values)
94
+ return [] unless values
95
+ encoder = field_value_encoder.new(list: list)
96
+ values.map { |k, v| encoder.decode(k => v) }
97
+ end
98
+
99
+ def field_value_encoder
100
+ @field_value_encoder ||= RelateIq::Utils::FieldValueEncoder
101
+ end
102
+
103
+ def list
104
+ List.find(list_id)
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,12 @@
1
+ module RelateIq
2
+ class ServiceFactory
3
+ def self.get_endpoint(endpoint)
4
+ RestClient::Resource.new(
5
+ "#{RelateIq.configuration.base_url}/#{endpoint}",
6
+ user: RelateIq.configuration.username,
7
+ password: RelateIq.configuration.password,
8
+ headers: { content_type: :json, accept: :json }
9
+ )
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,73 @@
1
+ module RelateIq
2
+ module Utils
3
+ class FieldValueEncoder
4
+ attr_accessor :list
5
+
6
+ def initialize(attrs = {})
7
+ @list = attrs.fetch(:list)
8
+ end
9
+
10
+ def encode(decoded_value)
11
+ return {} if decoded_value.nil?
12
+ name = decoded_value.keys[0]
13
+ values = decoded_value.values[0]
14
+ field = find_field_by_name(name)
15
+ encoded_value = encode_values(field, values)
16
+ return {} if encoded_value == []
17
+ { "#{field[:id]}" => encoded_value }
18
+ end
19
+
20
+ def decode(encoded_value)
21
+ return {} if encoded_value.nil?
22
+ id = encoded_value.keys[0]
23
+ values = encoded_value.values[0]
24
+ field = find_field(id)
25
+ { "#{field[:name]}" => decode_values(field, values) }
26
+ end
27
+
28
+ private
29
+
30
+ def decode_values(field, field_values)
31
+ result = []
32
+ field_values.each { |fv| result << list_option_value(field, fv[:raw], 'id', 'display') }
33
+ result.count > 1 ? result : result[0]
34
+ end
35
+
36
+ def encode_values(field, field_values)
37
+ result = []
38
+ to_array(field_values).each do |fv|
39
+ list_option = list_option_value(field, fv, 'display', 'id')
40
+ result << { 'raw' => list_option } unless list_option.nil?
41
+ end
42
+ result
43
+ end
44
+
45
+ def list_option_value(field, value, key, value_key)
46
+ return nil if value.nil?
47
+ list_options = field[:listOptions]
48
+ if list_options && list_options.count > 0
49
+ option = list_options.find { |lo| lo[key.to_sym].downcase == value.downcase }
50
+ option ||= fail(FieldListOptionNotFoundError, key => value)
51
+ option[value_key.to_sym]
52
+ else
53
+ value
54
+ end
55
+ end
56
+
57
+ def find_field_by_name(name)
58
+ list.fields.find { |f| f[:name] == name } || fail(FieldNotFoundError, name)
59
+ end
60
+
61
+ def find_field(id)
62
+ list.fields.find { |f| f[:id] == id.to_s } || fail(FieldNotFoundError, id)
63
+ end
64
+
65
+ def to_array(value)
66
+ value.is_a?(Array) ? value : [value]
67
+ end
68
+ end
69
+
70
+ class FieldNotFoundError < StandardError; end
71
+ class FieldListOptionNotFoundError < StandardError; end
72
+ end
73
+ end
@@ -0,0 +1,3 @@
1
+ module RelateIq
2
+ VERSION = "0.1.0"
3
+ end
data/relateiq.gemspec ADDED
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'relateiq/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'relateiq_client'
8
+ s.version = RelateIq::VERSION
9
+ s.authors = ['Dorian Karter']
10
+ s.email = 'jobs@doriankarter.com'
11
+
12
+ s.summary = 'Wrapper client for RelateIQ API'
13
+ s.description = 'Wrapper client for RelateIQ allows using RelateIQ API from ruby'
14
+ s.homepage = 'https://github.com/dkarter/relate_iq_client'
15
+ s.license = 'MIT'
16
+
17
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
19
+ s.bindir = 'bin'
20
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ s.require_paths = [ 'lib' ]
22
+
23
+ s.add_dependency 'rest-client', '~> 1.7'
24
+
25
+ s.add_development_dependency 'bundler', '~> 1.7'
26
+ s.add_development_dependency 'rake', '~> 10.0'
27
+ s.add_development_dependency 'rspec', '~>3.1'
28
+ s.add_development_dependency 'pry', '~> 0.10'
29
+ s.add_development_dependency 'pry-stack_explorer', '~> 0.4.9'
30
+ s.add_development_dependency 'zenflow'
31
+ s.add_development_dependency 'rubocop'
32
+ s.add_development_dependency 'simplecov'
33
+ s.add_development_dependency 'simplecov-json'
34
+ s.add_development_dependency 'cadre'
35
+ s.add_development_dependency 'codeclimate-test-reporter'
36
+ s.add_development_dependency 'webmock'
37
+ end
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "accountid",
3
+ "modifiedDate": 1423507504147,
4
+ "name": "Bolstr, Inc.",
5
+ "fieldValues": {}
6
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "id": "contactid",
3
+ "modifiedDate": 1424713865596,
4
+ "properties": {
5
+ "address": [
6
+ {
7
+ "value": "688 Dink rest, East Lu, Z2K 8OW",
8
+ "metadata": {}
9
+ }
10
+ ],
11
+ "company": [
12
+ {
13
+ "value": "Bolstr",
14
+ "metadata": {}
15
+ },
16
+ {
17
+ "value": "Bolstr, Inc.",
18
+ "metadata": {}
19
+ }
20
+ ],
21
+ "phone": [
22
+ {
23
+ "value": "+44 (0)5426658700",
24
+ "metadata": {}
25
+ }
26
+ ],
27
+ "name": [
28
+ {
29
+ "value": "Kipp Rice",
30
+ "metadata": {}
31
+ }
32
+ ],
33
+ "email": [
34
+ {
35
+ "value": "gulgowski.devyn@example.com",
36
+ "metadata": {}
37
+ }
38
+ ],
39
+ "liurl": [
40
+ {
41
+ "value": "https://www.linkedin.com/in/doriankarter",
42
+ "metadata": {}
43
+ }
44
+ ]
45
+ }
46
+ }
File without changes
@@ -0,0 +1,34 @@
1
+ {
2
+ "objects": [
3
+ {
4
+ "id": "contactid",
5
+ "modifiedDate": 1424713865596,
6
+ "properties": {
7
+ "address": [
8
+ {
9
+ "value": "688 Dink rest, East Lu, Z2K 8OW",
10
+ "metadata": {}
11
+ }
12
+ ],
13
+ "phone": [
14
+ {
15
+ "value": "+44 (0)5426658700",
16
+ "metadata": {}
17
+ }
18
+ ],
19
+ "name": [
20
+ {
21
+ "value": "Kipp Rice",
22
+ "metadata": {}
23
+ }
24
+ ],
25
+ "email": [
26
+ {
27
+ "value": "gulgowski.devyn@example.com",
28
+ "metadata": {}
29
+ }
30
+ ]
31
+ }
32
+ }
33
+ ]
34
+ }
@@ -0,0 +1,72 @@
1
+ {
2
+ "id": "listitemid",
3
+ "listId": "list2id",
4
+ "version": 1,
5
+ "createdDate": 1417755155000,
6
+ "modifiedDate": 1421866566579,
7
+ "name": "Mack Koch",
8
+ "accountId": "accountid",
9
+ "contactIds": [
10
+ "contactid1",
11
+ "contactid2"
12
+ ],
13
+ "fieldValues": {
14
+ "0": [
15
+ {
16
+ "raw": "3"
17
+ }
18
+ ],
19
+ "15": [
20
+ {
21
+ "raw": "Boulder"
22
+ }
23
+ ],
24
+ "25": [
25
+ {
26
+ "raw": "5"
27
+ }
28
+ ],
29
+ "27": [
30
+ {
31
+ "raw": "30000"
32
+ }
33
+ ],
34
+ "40": [
35
+ {
36
+ "raw": "1417755155526"
37
+ }
38
+ ],
39
+ "43": [
40
+ {
41
+ "raw": "ec805c1d1effbc2768ce94108e30eeae74e15931"
42
+ }
43
+ ],
44
+ "44": [
45
+ {
46
+ "raw": "1"
47
+ }
48
+ ],
49
+ "45": [
50
+ {
51
+ "raw": "3"
52
+ }
53
+ ],
54
+ "46": [
55
+ {
56
+ "raw": "18"
57
+ }
58
+ ]
59
+ },
60
+ "linkedItemIds": {
61
+ "5ff139a60e6220c263558fbc0f26786050a70b34.accounts": [
62
+ {
63
+ "itemId": "4d7f9d97f6c00d41fcbfffad489f60f9d8cbfeb1"
64
+ }
65
+ ],
66
+ "list.cd669e1c0fa10a6a98639489807851415d3499d1": [
67
+ {
68
+ "itemId": "d7e41e76a945d9811aa7981fdd6a4ee5c28fdc05"
69
+ }
70
+ ]
71
+ }
72
+ }