riq 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +42 -0
- data/.yardopts +2 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +33 -0
- data/lib/riq.rb +103 -0
- data/lib/riq/account.rb +82 -0
- data/lib/riq/batch_manager.rb +133 -0
- data/lib/riq/client.rb +130 -0
- data/lib/riq/contact.rb +158 -0
- data/lib/riq/error.rb +56 -0
- data/lib/riq/event.rb +73 -0
- data/lib/riq/list.rb +89 -0
- data/lib/riq/list_item.rb +119 -0
- data/lib/riq/list_item_manager.rb +13 -0
- data/lib/riq/riq_obj.rb +105 -0
- data/lib/riq/user.rb +47 -0
- data/riq.gemspec +29 -0
- data/test/test.rb +4 -0
- data/test/test_account.rb +44 -0
- data/test/test_batch_manager.rb +72 -0
- data/test/test_contact.rb +62 -0
- data/test/test_event.rb +56 -0
- data/test/test_list_item.rb +42 -0
- metadata +33 -3
data/lib/riq/contact.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
require_relative 'riq_obj'
|
2
|
+
using RIQExtensions
|
3
|
+
|
4
|
+
module RIQ
|
5
|
+
# Contacts represent people in an Organization’s address book.
|
6
|
+
class Contact < RIQObject
|
7
|
+
attr_accessor :properties
|
8
|
+
|
9
|
+
# (see RIQObject#node)
|
10
|
+
def node
|
11
|
+
self.class.node(@id)
|
12
|
+
end
|
13
|
+
|
14
|
+
# (see RIQObject.node)
|
15
|
+
def self.node(id = nil)
|
16
|
+
"contacts/#{id}"
|
17
|
+
end
|
18
|
+
|
19
|
+
# (see RIQObject#data)
|
20
|
+
def data
|
21
|
+
{
|
22
|
+
id: @id,
|
23
|
+
properties: @properties
|
24
|
+
# modified_date: @modified_date
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
# @!macro [new] prop
|
29
|
+
# @return [Array] all of the values for $0
|
30
|
+
def name
|
31
|
+
get_prop(:name)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @macro prop
|
35
|
+
def phone
|
36
|
+
get_prop(:phone)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @macro prop
|
40
|
+
def email
|
41
|
+
get_prop(:email)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @macro prop
|
45
|
+
def address
|
46
|
+
get_prop(:address)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Adds property with correct scaffolding
|
50
|
+
# @param prop [Symbol] Type Property to add, such as :name or :email
|
51
|
+
# @param val [String, Array] Value(s) to add
|
52
|
+
# @return [Array] Values for that property after the add
|
53
|
+
def add(prop, val)
|
54
|
+
# validate(prop)
|
55
|
+
prop = prop.to_sym
|
56
|
+
@properties[prop] = [] unless @properties.include? prop
|
57
|
+
|
58
|
+
if val.is_a? Array
|
59
|
+
val.each do |i|
|
60
|
+
add(prop, i)
|
61
|
+
end
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
65
|
+
raise RIQError, 'Values must be strings' unless val.is_a? String
|
66
|
+
|
67
|
+
# don't add duplicate
|
68
|
+
if @properties[prop].select{|p| p[:value] == val}.empty?
|
69
|
+
@properties[prop] << {value: val, metadata: {}}
|
70
|
+
end
|
71
|
+
send(prop)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Removes property from hash
|
75
|
+
# @param prop [Symbol] Type Property to remove, such as :name or :email
|
76
|
+
# @param val [String, Array] Value(s) to remove
|
77
|
+
# @return [Array] Values for that property after the remove
|
78
|
+
def remove(prop, val)
|
79
|
+
# validate(prop)
|
80
|
+
prop = prop.to_sym
|
81
|
+
|
82
|
+
if val.is_a? Array
|
83
|
+
val.each do |i|
|
84
|
+
remove(prop, i)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if @properties.include? prop
|
89
|
+
@properties[prop] = @properties[prop].reject{|p| p[:value] == val}
|
90
|
+
end
|
91
|
+
send(prop)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Edits an existing object based on matching email(s) or saves a new object
|
95
|
+
# @see RIQObject#save
|
96
|
+
def upsert
|
97
|
+
save({_upsert: 'email'})
|
98
|
+
end
|
99
|
+
|
100
|
+
# @param prop [Symbol] The property to fetch. One of [:name, :phone, :email, :address]
|
101
|
+
# @param val [String] The value to get info on, such as 'name@domain.com'
|
102
|
+
# @return [Hash] metadata and other info about a given property
|
103
|
+
def info(prop, val)
|
104
|
+
# validate(prop)
|
105
|
+
|
106
|
+
@properties[prop].select{|p| p[:value] == val}.first
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def init(obj = nil)
|
112
|
+
unless obj.nil?
|
113
|
+
@id = obj[:id]
|
114
|
+
@modified_date = obj[:modified_date].cut_milis if obj[:modified_date]
|
115
|
+
@properties = {}
|
116
|
+
obj[:properties].each do |k,v|
|
117
|
+
raise RIQError, "Properties must be arrays, #{k} wasn't" if !v.is_a?(Array)
|
118
|
+
|
119
|
+
v.each do |i|
|
120
|
+
unless i.is_a?(Hash)
|
121
|
+
add(k, i)
|
122
|
+
else
|
123
|
+
@properties[k] = [] unless @properties.include?(k)
|
124
|
+
@properties[k] << i
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
else
|
129
|
+
@id = nil
|
130
|
+
@properties = {}
|
131
|
+
end
|
132
|
+
self
|
133
|
+
end
|
134
|
+
|
135
|
+
# unused because we actually put all sorts of stuff in there
|
136
|
+
def validate(prop)
|
137
|
+
raise RIQError, %q(Invalid property. Use [:name | :phone | :email | :address] instead) unless [:name, :phone, :email, :address].include? prop
|
138
|
+
end
|
139
|
+
|
140
|
+
def get_prop(prop)
|
141
|
+
if @properties.include? prop
|
142
|
+
@properties[prop].map{|p| p[:value]}
|
143
|
+
else
|
144
|
+
[]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class << self
|
150
|
+
# Convenience method to create new Contacts
|
151
|
+
# @param id [String, nil] create a blank Contact object or
|
152
|
+
# fetch an existing one by id.
|
153
|
+
# @return [Contact]
|
154
|
+
def contact(id = nil)
|
155
|
+
Contact.new(id)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
data/lib/riq/error.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module RIQ
|
2
|
+
# Base exception class for our errors.
|
3
|
+
class RIQError < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
# Hasn't been implemented yet. Doesn't get used often.
|
7
|
+
class NotImplementedError < RIQError
|
8
|
+
end
|
9
|
+
|
10
|
+
# Raised when an ObjectId fetch doesn't return anything.
|
11
|
+
class NotFoundError < RIQError
|
12
|
+
end
|
13
|
+
|
14
|
+
# Main error that includes info about the request and what went wrong.
|
15
|
+
class HTTPError < RIQError
|
16
|
+
attr_accessor :code
|
17
|
+
attr_accessor :message
|
18
|
+
attr_accessor :response
|
19
|
+
|
20
|
+
def initialize(resp)
|
21
|
+
# build response message
|
22
|
+
message = "\n[#{resp.code}] #{resp.message} : "
|
23
|
+
unless resp.parsed_response.nil?
|
24
|
+
begin
|
25
|
+
m = resp.parsed_response.fetch('errorMessage', 'no message')
|
26
|
+
rescue
|
27
|
+
# parse returned HTML
|
28
|
+
reg = resp.parsed_response.match(/<pre>(.*)<\/pre>/)
|
29
|
+
unless reg.nil?
|
30
|
+
m = reg[1].strip
|
31
|
+
else
|
32
|
+
m = 'no message'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
message += "<#{m}>"
|
36
|
+
end
|
37
|
+
|
38
|
+
# pull out request info
|
39
|
+
req = resp.request
|
40
|
+
unless req.nil?
|
41
|
+
message += "\n Request: #{req.http_method} #{req.last_uri.to_s}"
|
42
|
+
unless req.raw_body.nil?
|
43
|
+
message += "\n #{req.raw_body}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
@message = message
|
48
|
+
@response = resp
|
49
|
+
end
|
50
|
+
|
51
|
+
# used to print the error nicely
|
52
|
+
def to_s
|
53
|
+
@message || super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/riq/event.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require_relative 'riq_obj'
|
2
|
+
using RIQExtensions
|
3
|
+
|
4
|
+
module RIQ
|
5
|
+
# Events represent interactions involving a Contact associated with a List Item.
|
6
|
+
class Event < RIQObject
|
7
|
+
attr_accessor :subject
|
8
|
+
attr_accessor :body
|
9
|
+
# attr_reader :participant_ids
|
10
|
+
|
11
|
+
# (see RIQObject#node)
|
12
|
+
def node
|
13
|
+
self.class.node
|
14
|
+
end
|
15
|
+
|
16
|
+
# (see RIQObject#node)
|
17
|
+
def self.node
|
18
|
+
"events"
|
19
|
+
end
|
20
|
+
|
21
|
+
# (see RIQObject#data)
|
22
|
+
def data
|
23
|
+
{
|
24
|
+
subject: @subject,
|
25
|
+
body: @body,
|
26
|
+
participant_ids: @participant_ids
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param type [Symbol] One of :email or :phone
|
31
|
+
# @param value [String] An email or phone number for the contact
|
32
|
+
def add_participant(type, value)
|
33
|
+
raise RIQError, 'Type must be :email or :phone' unless [:email, :phone].include?(type)
|
34
|
+
@participant_ids << {type: type, value: value}
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Array] Immutable copy of participant_ids
|
38
|
+
def participant_ids
|
39
|
+
@participant_ids.dup
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Hash] Success message, if successful.
|
43
|
+
def save
|
44
|
+
# there are no options to pass for event save
|
45
|
+
@client.put(node, payload, options: nil)
|
46
|
+
{status: 204, message: 'No Content'}
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def init(obj = nil)
|
51
|
+
unless obj.nil?
|
52
|
+
@subject = obj[:subject]
|
53
|
+
@body = obj[:body]
|
54
|
+
@participant_ids = []
|
55
|
+
obj[:participant_ids].each{|o| add_participant(o[:type], o[:value])}
|
56
|
+
else
|
57
|
+
@subject = nil
|
58
|
+
@body = nil
|
59
|
+
@participant_ids = []
|
60
|
+
end
|
61
|
+
self
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class << self
|
66
|
+
# Convenience method to create new Events
|
67
|
+
# @param obj [Hash] Info to parse into event
|
68
|
+
# @return [Event]
|
69
|
+
def event(obj = nil)
|
70
|
+
Event.new(obj)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/riq/list.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require_relative 'riq_obj'
|
2
|
+
|
3
|
+
module RIQ
|
4
|
+
# A List is an object that can be created and customized by a User to represent
|
5
|
+
# Accounts (companies) or Contacts (people) in a process (such as a sales pipeline).
|
6
|
+
class List < RIQObject
|
7
|
+
# can't create a list through API, so these don't need to write
|
8
|
+
attr_reader :title
|
9
|
+
attr_reader :type
|
10
|
+
attr_reader :list_items
|
11
|
+
# for consistency
|
12
|
+
alias_method :name, :title
|
13
|
+
|
14
|
+
# (see RIQObject#initialize)
|
15
|
+
def initialize(id = nil)
|
16
|
+
super
|
17
|
+
@list_items = ListItemManager.new(@id)
|
18
|
+
end
|
19
|
+
|
20
|
+
# (see RIQObject#node)
|
21
|
+
def node
|
22
|
+
self.class.node(@id)
|
23
|
+
end
|
24
|
+
|
25
|
+
# (see RIQObject.node)
|
26
|
+
def self.node(id = nil)
|
27
|
+
"lists/#{id}"
|
28
|
+
end
|
29
|
+
|
30
|
+
# (see RIQObject#data)
|
31
|
+
def data
|
32
|
+
{
|
33
|
+
id: @id,
|
34
|
+
title: @title,
|
35
|
+
type: @type,
|
36
|
+
fields: @fields
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
# Overwriting parent because lists can't be saved through the API
|
41
|
+
def save
|
42
|
+
raise NotImplementedError, "Lists can't be edited through the API"
|
43
|
+
end
|
44
|
+
|
45
|
+
# Gets field if it exists
|
46
|
+
# @param id [String, Integer] field ID
|
47
|
+
# @return [Hash, nil] info on the field specified
|
48
|
+
def fields(id = nil)
|
49
|
+
unless id.nil?
|
50
|
+
@fields.select{|f| f['id'] == id.to_s}.first
|
51
|
+
else
|
52
|
+
@fields
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Convenience method for fetching or creating a listitem from the given list
|
57
|
+
# @param oid [String, nil] ObjectId
|
58
|
+
def list_item(oid = nil)
|
59
|
+
RIQ::ListItem.new(oid, lid: @id)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def init(obj = nil)
|
65
|
+
unless obj.nil?
|
66
|
+
@id = obj[:id]
|
67
|
+
@title = obj[:title]
|
68
|
+
@type = obj[:listType]
|
69
|
+
@fields = obj[:fields]
|
70
|
+
else
|
71
|
+
@id = nil
|
72
|
+
@title = nil
|
73
|
+
@type = nil
|
74
|
+
@fields = nil
|
75
|
+
end
|
76
|
+
self
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class << self
|
81
|
+
# Convenience method to create new Lists
|
82
|
+
# @param id [String, nil] create a blank List object or
|
83
|
+
# fetch an existing one by id.
|
84
|
+
# @return [List]
|
85
|
+
def list(id = nil)
|
86
|
+
List.new(id)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require_relative 'riq_obj'
|
2
|
+
using RIQExtensions
|
3
|
+
|
4
|
+
module RIQ
|
5
|
+
# A List Item is a row in a List.
|
6
|
+
class ListItem < RIQObject
|
7
|
+
attr_accessor :name
|
8
|
+
attr_accessor :field_values
|
9
|
+
attr_accessor :account_id
|
10
|
+
attr_accessor :contact_ids
|
11
|
+
attr_accessor :list_id
|
12
|
+
|
13
|
+
attr_reader :modified_date
|
14
|
+
attr_reader :created_date
|
15
|
+
|
16
|
+
def initialize(id = nil, lid: nil)
|
17
|
+
if id.is_a? Hash
|
18
|
+
super(id)
|
19
|
+
elsif id.nil? && lid.nil?
|
20
|
+
super(nil)
|
21
|
+
elsif id.nil? && !lid.nil?
|
22
|
+
super(nil)
|
23
|
+
@list_id = lid
|
24
|
+
elsif id.nil? || lid.nil?
|
25
|
+
raise RIQError, 'ObjectID and List ID are required'
|
26
|
+
else
|
27
|
+
super("#{lid}/listitems/#{id}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# (see RIQObject#node)
|
32
|
+
def node
|
33
|
+
self.class.node(@list_id, @id)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @note this is the only object for which you have to include two params
|
37
|
+
# @param lid [String] ListId that the lit item belongs to
|
38
|
+
# @param oid [String] ObjectId for the object
|
39
|
+
def self.node(lid = nil, oid = nil)
|
40
|
+
# weird workaround for fetching node on init
|
41
|
+
if lid.nil? && !oid.nil?
|
42
|
+
"lists/#{oid}"
|
43
|
+
else
|
44
|
+
"lists/#{lid || @list_id}/listitems/#{oid}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# (see RIQObject#data)
|
49
|
+
def data
|
50
|
+
{
|
51
|
+
name: @name,
|
52
|
+
account_id: @account_id,
|
53
|
+
contact_ids: @contact_ids.flatten,
|
54
|
+
id: @id,
|
55
|
+
list_id: @list_id,
|
56
|
+
field_values: @field_values,
|
57
|
+
modified_date: @modified_date
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
# (see RIQObject#payload)
|
62
|
+
def payload
|
63
|
+
pld = {}
|
64
|
+
data.each do |k, v|
|
65
|
+
if k == :field_values
|
66
|
+
pld['fieldValues'] = @field_values.to_raw
|
67
|
+
elsif k['_']
|
68
|
+
pld[k.to_cam] = v
|
69
|
+
else
|
70
|
+
pld[k] = v
|
71
|
+
end
|
72
|
+
end
|
73
|
+
pld.to_json
|
74
|
+
end
|
75
|
+
|
76
|
+
# @overload field_value(key)
|
77
|
+
# @param key [String, Integer]
|
78
|
+
# @return [Array] Value of key
|
79
|
+
# @overload field_value(key, value)
|
80
|
+
# Sets key to value
|
81
|
+
# @param key [String, Integer] Key to set
|
82
|
+
# @param value [#to_s] Sets key to value
|
83
|
+
def field_value(key, value = nil)
|
84
|
+
# TODO: double check that this works with arrays of stuff
|
85
|
+
# or, have a format function that casts ints to string on save
|
86
|
+
if value.nil?
|
87
|
+
@field_values.fetch(key.to_sym, nil)
|
88
|
+
else
|
89
|
+
@field_values[key.to_sym] = value.to_s
|
90
|
+
{key.to_sym => value.to_s}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def init(obj = nil)
|
97
|
+
unless obj.nil?
|
98
|
+
@id = obj[:id]
|
99
|
+
@list_id = obj[:list_id]
|
100
|
+
@name = obj[:name]
|
101
|
+
@field_values = obj[:field_values] ? obj[:field_values].from_raw : {}
|
102
|
+
@account_id = obj[:account_id]
|
103
|
+
@contact_ids = obj[:contact_ids] || []
|
104
|
+
@modified_date = obj[:modified_date].cut_milis if obj[:modified_date]
|
105
|
+
@created_date = obj[:creaeted_date].cut_milis if obj[:creaeted_date]
|
106
|
+
else
|
107
|
+
@id = nil
|
108
|
+
@list_id = nil
|
109
|
+
@name = nil
|
110
|
+
@field_values = {}
|
111
|
+
@account_id = nil
|
112
|
+
@contact_ids = []
|
113
|
+
@modified_date = nil
|
114
|
+
@created_date = nil
|
115
|
+
end
|
116
|
+
self
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|