followupboss_client 1.0.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.
- checksums.yaml +7 -0
- data/.env.example +12 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +149 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +882 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/followupboss_client.gemspec +43 -0
- data/lib/followupboss_client.rb +16 -0
- data/lib/fub_client/action_plan.rb +5 -0
- data/lib/fub_client/appointment.rb +42 -0
- data/lib/fub_client/appointment_outcome.rb +51 -0
- data/lib/fub_client/appointment_type.rb +51 -0
- data/lib/fub_client/call.rb +4 -0
- data/lib/fub_client/client.rb +200 -0
- data/lib/fub_client/compatibility.rb +18 -0
- data/lib/fub_client/configuration.rb +54 -0
- data/lib/fub_client/cookie_client.rb +190 -0
- data/lib/fub_client/custom_field.rb +5 -0
- data/lib/fub_client/deal.rb +41 -0
- data/lib/fub_client/deal_attachment.rb +61 -0
- data/lib/fub_client/deal_custom_field.rb +47 -0
- data/lib/fub_client/em_event.rb +5 -0
- data/lib/fub_client/email_template.rb +5 -0
- data/lib/fub_client/event.rb +8 -0
- data/lib/fub_client/group.rb +58 -0
- data/lib/fub_client/her_patch.rb +101 -0
- data/lib/fub_client/identity.rb +33 -0
- data/lib/fub_client/message.rb +41 -0
- data/lib/fub_client/middleware/authentication.rb +26 -0
- data/lib/fub_client/middleware/cookie_authentication.rb +61 -0
- data/lib/fub_client/middleware/parser.rb +59 -0
- data/lib/fub_client/middleware.rb +8 -0
- data/lib/fub_client/note.rb +4 -0
- data/lib/fub_client/people_relationship.rb +34 -0
- data/lib/fub_client/person.rb +5 -0
- data/lib/fub_client/person_attachment.rb +50 -0
- data/lib/fub_client/pipeline.rb +45 -0
- data/lib/fub_client/property.rb +26 -0
- data/lib/fub_client/rails8_patch.rb +39 -0
- data/lib/fub_client/resource.rb +33 -0
- data/lib/fub_client/shared_inbox.rb +389 -0
- data/lib/fub_client/smart_list.rb +5 -0
- data/lib/fub_client/stage.rb +39 -0
- data/lib/fub_client/task.rb +18 -0
- data/lib/fub_client/team.rb +65 -0
- data/lib/fub_client/team_inbox.rb +65 -0
- data/lib/fub_client/text_message.rb +46 -0
- data/lib/fub_client/text_message_template.rb +49 -0
- data/lib/fub_client/user.rb +4 -0
- data/lib/fub_client/version.rb +3 -0
- data/lib/fub_client/webhook.rb +47 -0
- data/lib/fub_client.rb +61 -0
- data/scripts/test_api.rb +110 -0
- data/scripts/test_shared_inbox.rb +90 -0
- metadata +335 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
module FubClient
|
|
2
|
+
module SharedInboxMethods
|
|
3
|
+
def messages(limit = 20, offset = 0)
|
|
4
|
+
inbox_id = is_a?(Hash) ? self[:id] : id
|
|
5
|
+
return [] unless inbox_id
|
|
6
|
+
|
|
7
|
+
begin
|
|
8
|
+
conn = FubClient::SharedInbox.create_faraday_connection
|
|
9
|
+
return [] unless conn
|
|
10
|
+
|
|
11
|
+
query = "?limit=#{limit}&offset=#{offset}"
|
|
12
|
+
response = conn.get("/api/v1/sharedInboxes/#{inbox_id}/messages#{query}")
|
|
13
|
+
|
|
14
|
+
if ENV['DEBUG']
|
|
15
|
+
puts "Fetching messages for inbox #{inbox_id}"
|
|
16
|
+
puts "Response status: #{response.status}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if response.status == 200
|
|
20
|
+
data = JSON.parse(response.body, symbolize_names: true)
|
|
21
|
+
messages = data[:messages] || []
|
|
22
|
+
puts "Found #{messages.count} messages" if ENV['DEBUG']
|
|
23
|
+
messages
|
|
24
|
+
else
|
|
25
|
+
puts "Error: HTTP #{response.status} - #{response.body}" if ENV['DEBUG']
|
|
26
|
+
[]
|
|
27
|
+
end
|
|
28
|
+
rescue StandardError => e
|
|
29
|
+
puts "Error fetching messages: #{e.message}" if ENV['DEBUG']
|
|
30
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
31
|
+
[]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def settings
|
|
36
|
+
inbox_id = is_a?(Hash) ? self[:id] : id
|
|
37
|
+
return {} unless inbox_id
|
|
38
|
+
|
|
39
|
+
begin
|
|
40
|
+
conn = FubClient::SharedInbox.create_faraday_connection
|
|
41
|
+
return {} unless conn
|
|
42
|
+
|
|
43
|
+
response = conn.get("/api/v1/sharedInboxes/#{inbox_id}/settings")
|
|
44
|
+
|
|
45
|
+
if ENV['DEBUG']
|
|
46
|
+
puts "Fetching settings for inbox #{inbox_id}"
|
|
47
|
+
puts "Response status: #{response.status}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
if response.status == 200
|
|
51
|
+
data = JSON.parse(response.body, symbolize_names: true)
|
|
52
|
+
settings = data[:settings] || {}
|
|
53
|
+
puts 'Settings retrieved successfully' if ENV['DEBUG']
|
|
54
|
+
settings
|
|
55
|
+
else
|
|
56
|
+
puts "Error: HTTP #{response.status} - #{response.body}" if ENV['DEBUG']
|
|
57
|
+
{}
|
|
58
|
+
end
|
|
59
|
+
rescue StandardError => e
|
|
60
|
+
puts "Error fetching settings: #{e.message}" if ENV['DEBUG']
|
|
61
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
62
|
+
{}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def conversations(limit = 20, offset = 0, filter = nil)
|
|
67
|
+
inbox_id = is_a?(Hash) ? self[:id] : id
|
|
68
|
+
return [] unless inbox_id
|
|
69
|
+
|
|
70
|
+
begin
|
|
71
|
+
conn = FubClient::SharedInbox.create_faraday_connection
|
|
72
|
+
return [] unless conn
|
|
73
|
+
|
|
74
|
+
query = "?limit=#{limit}&offset=#{offset}"
|
|
75
|
+
query += "&filter=#{URI.encode_www_form_component(filter)}" if filter
|
|
76
|
+
|
|
77
|
+
response = conn.get("/api/v1/sharedInboxes/#{inbox_id}/conversations#{query}")
|
|
78
|
+
|
|
79
|
+
if ENV['DEBUG']
|
|
80
|
+
puts "Fetching conversations for inbox #{inbox_id}"
|
|
81
|
+
puts "Response status: #{response.status}"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if response.status == 200
|
|
85
|
+
data = JSON.parse(response.body, symbolize_names: true)
|
|
86
|
+
conversations = data[:conversations] || []
|
|
87
|
+
puts "Found #{conversations.count} conversations" if ENV['DEBUG']
|
|
88
|
+
conversations
|
|
89
|
+
else
|
|
90
|
+
puts "Error: HTTP #{response.status} - #{response.body}" if ENV['DEBUG']
|
|
91
|
+
[]
|
|
92
|
+
end
|
|
93
|
+
rescue StandardError => e
|
|
94
|
+
puts "Error fetching conversations: #{e.message}" if ENV['DEBUG']
|
|
95
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
96
|
+
[]
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class SharedInbox < Resource
|
|
102
|
+
collection_path 'sharedInboxes'
|
|
103
|
+
root_element :shared_inbox
|
|
104
|
+
include_root_in_json true
|
|
105
|
+
|
|
106
|
+
def self.all_inboxes
|
|
107
|
+
puts 'Calling SharedInbox.all_inboxes using direct cookie authentication' if ENV['DEBUG']
|
|
108
|
+
|
|
109
|
+
client = FubClient::Client.instance
|
|
110
|
+
cookies = client.cookies
|
|
111
|
+
subdomain = client.subdomain
|
|
112
|
+
|
|
113
|
+
if !cookies || cookies.empty?
|
|
114
|
+
puts 'Error: No cookies available for authentication' if ENV['DEBUG']
|
|
115
|
+
return []
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
if !subdomain || subdomain.empty?
|
|
119
|
+
puts 'Error: No subdomain set for authentication' if ENV['DEBUG']
|
|
120
|
+
return []
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
conn = Faraday.new(url: "https://#{subdomain}.followupboss.com") do |f|
|
|
124
|
+
f.headers['Cookie'] = cookies
|
|
125
|
+
f.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'
|
|
126
|
+
f.headers['Accept-Language'] = 'en-US,en;q=0.9'
|
|
127
|
+
f.headers['X-Requested-With'] = 'XMLHttpRequest'
|
|
128
|
+
f.headers['X-System'] = 'fub-spa'
|
|
129
|
+
f.headers['User-Agent'] =
|
|
130
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
|
|
131
|
+
f.adapter :net_http
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
response = conn.get('/api/v1/sharedInboxes?showAllBypass=true&limit=20&offset=0')
|
|
135
|
+
|
|
136
|
+
if ENV['DEBUG']
|
|
137
|
+
puts 'Request headers:'
|
|
138
|
+
conn.headers.each do |k, v|
|
|
139
|
+
if k.downcase == 'cookie' && v.length > 50
|
|
140
|
+
puts " #{k}: #{v[0..50]}..."
|
|
141
|
+
else
|
|
142
|
+
puts " #{k}: #{v}"
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
puts "Response status: #{response.status}"
|
|
146
|
+
puts "Response body: #{response.body[0..100]}..." if response.body && response.body.length > 100
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
if response.status == 200
|
|
150
|
+
data = JSON.parse(response.body, symbolize_names: true)
|
|
151
|
+
inboxes = data[:sharedInboxes] || []
|
|
152
|
+
puts "Found #{inboxes.count} shared inboxes via direct request" if ENV['DEBUG']
|
|
153
|
+
inboxes
|
|
154
|
+
else
|
|
155
|
+
puts "Error: HTTP #{response.status} - #{response.body}" if ENV['DEBUG']
|
|
156
|
+
[]
|
|
157
|
+
end
|
|
158
|
+
rescue StandardError => e
|
|
159
|
+
puts "Error in all_inboxes: #{e.message}" if ENV['DEBUG']
|
|
160
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
161
|
+
[]
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def self.get_inbox(id)
|
|
165
|
+
puts "Calling SharedInbox.get_inbox(#{id}) using direct cookie authentication" if ENV['DEBUG']
|
|
166
|
+
|
|
167
|
+
client = FubClient::Client.instance
|
|
168
|
+
cookies = client.cookies
|
|
169
|
+
subdomain = client.subdomain
|
|
170
|
+
|
|
171
|
+
if !cookies || cookies.empty?
|
|
172
|
+
puts 'Error: No cookies available for authentication' if ENV['DEBUG']
|
|
173
|
+
return nil
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
if !subdomain || subdomain.empty?
|
|
177
|
+
puts 'Error: No subdomain set for authentication' if ENV['DEBUG']
|
|
178
|
+
return nil
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
conn = Faraday.new(url: "https://#{subdomain}.followupboss.com") do |f|
|
|
182
|
+
f.headers['Cookie'] = cookies
|
|
183
|
+
f.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'
|
|
184
|
+
f.headers['Accept-Language'] = 'en-US,en;q=0.9'
|
|
185
|
+
f.headers['X-Requested-With'] = 'XMLHttpRequest'
|
|
186
|
+
f.headers['X-System'] = 'fub-spa'
|
|
187
|
+
f.headers['User-Agent'] =
|
|
188
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
|
|
189
|
+
f.adapter :net_http
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
response = conn.get("/api/v1/sharedInboxes/#{id}")
|
|
193
|
+
|
|
194
|
+
if ENV['DEBUG']
|
|
195
|
+
puts "Response status: #{response.status}"
|
|
196
|
+
puts "Response body: #{response.body[0..100]}..." if response.body && response.body.length > 100
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
if response.status == 200
|
|
200
|
+
if ENV['DEBUG']
|
|
201
|
+
puts "Raw response body: #{response.body[0..200]}..." if response.body.length > 200
|
|
202
|
+
puts "Raw response body: #{response.body}" if response.body.length <= 200
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
data = JSON.parse(response.body, symbolize_names: true)
|
|
206
|
+
|
|
207
|
+
if ENV['DEBUG']
|
|
208
|
+
puts "Parsed data keys: #{data.keys.inspect}"
|
|
209
|
+
puts "Parsed data type: #{data.class}"
|
|
210
|
+
puts "Has :id key? #{data.key?(:id)}"
|
|
211
|
+
puts "ID value: #{data[:id]}" if data.key?(:id)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
if data.is_a?(Hash) && !data.empty?
|
|
215
|
+
puts "Found inbox with ID #{id} via direct request" if ENV['DEBUG']
|
|
216
|
+
data.extend(SharedInboxMethods)
|
|
217
|
+
data
|
|
218
|
+
else
|
|
219
|
+
puts "Unexpected response structure: #{data.inspect}" if ENV['DEBUG']
|
|
220
|
+
nil
|
|
221
|
+
end
|
|
222
|
+
else
|
|
223
|
+
puts "Error: HTTP #{response.status} - #{response.body}" if ENV['DEBUG']
|
|
224
|
+
nil
|
|
225
|
+
end
|
|
226
|
+
rescue StandardError => e
|
|
227
|
+
puts "Error in get_inbox: #{e.message}" if ENV['DEBUG']
|
|
228
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
229
|
+
nil
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def self.create_faraday_connection
|
|
233
|
+
client = FubClient::Client.instance
|
|
234
|
+
cookies = client.cookies
|
|
235
|
+
subdomain = client.subdomain
|
|
236
|
+
|
|
237
|
+
if !cookies || cookies.empty?
|
|
238
|
+
puts 'Error: No cookies available for authentication' if ENV['DEBUG']
|
|
239
|
+
return nil
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
if !subdomain || subdomain.empty?
|
|
243
|
+
puts 'Error: No subdomain set for authentication' if ENV['DEBUG']
|
|
244
|
+
return nil
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
Faraday.new(url: "https://#{subdomain}.followupboss.com") do |f|
|
|
248
|
+
f.headers['Cookie'] = cookies
|
|
249
|
+
f.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'
|
|
250
|
+
f.headers['Accept-Language'] = 'en-US,en;q=0.9'
|
|
251
|
+
f.headers['X-Requested-With'] = 'XMLHttpRequest'
|
|
252
|
+
f.headers['X-System'] = 'fub-spa'
|
|
253
|
+
f.headers['User-Agent'] =
|
|
254
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36'
|
|
255
|
+
f.adapter :net_http
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def messages(limit = 20, offset = 0)
|
|
260
|
+
inbox_id = is_a?(Hash) ? self[:id] : id
|
|
261
|
+
return [] unless inbox_id
|
|
262
|
+
|
|
263
|
+
begin
|
|
264
|
+
conn = self.class.create_faraday_connection
|
|
265
|
+
return [] unless conn
|
|
266
|
+
|
|
267
|
+
query = "?limit=#{limit}&offset=#{offset}"
|
|
268
|
+
response = conn.get("/api/v1/sharedInboxes/#{inbox_id}/messages#{query}")
|
|
269
|
+
|
|
270
|
+
if ENV['DEBUG']
|
|
271
|
+
puts "Fetching messages for inbox #{inbox_id}"
|
|
272
|
+
puts "Response status: #{response.status}"
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
if response.status == 200
|
|
276
|
+
data = JSON.parse(response.body, symbolize_names: true)
|
|
277
|
+
messages = data[:messages] || []
|
|
278
|
+
puts "Found #{messages.count} messages" if ENV['DEBUG']
|
|
279
|
+
messages
|
|
280
|
+
else
|
|
281
|
+
puts "Error: HTTP #{response.status} - #{response.body}" if ENV['DEBUG']
|
|
282
|
+
[]
|
|
283
|
+
end
|
|
284
|
+
rescue StandardError => e
|
|
285
|
+
puts "Error fetching messages: #{e.message}" if ENV['DEBUG']
|
|
286
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
287
|
+
[]
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def settings
|
|
292
|
+
inbox_id = is_a?(Hash) ? self[:id] : id
|
|
293
|
+
return {} unless inbox_id
|
|
294
|
+
|
|
295
|
+
begin
|
|
296
|
+
conn = self.class.create_faraday_connection
|
|
297
|
+
return {} unless conn
|
|
298
|
+
|
|
299
|
+
response = conn.get("/api/v1/sharedInboxes/#{inbox_id}/settings")
|
|
300
|
+
|
|
301
|
+
if ENV['DEBUG']
|
|
302
|
+
puts "Fetching settings for inbox #{inbox_id}"
|
|
303
|
+
puts "Response status: #{response.status}"
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
if response.status == 200
|
|
307
|
+
data = JSON.parse(response.body, symbolize_names: true)
|
|
308
|
+
settings = data[:settings] || {}
|
|
309
|
+
puts 'Settings retrieved successfully' if ENV['DEBUG']
|
|
310
|
+
settings
|
|
311
|
+
else
|
|
312
|
+
puts "Error: HTTP #{response.status} - #{response.body}" if ENV['DEBUG']
|
|
313
|
+
{}
|
|
314
|
+
end
|
|
315
|
+
rescue StandardError => e
|
|
316
|
+
puts "Error fetching settings: #{e.message}" if ENV['DEBUG']
|
|
317
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
318
|
+
{}
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def update_settings(settings_hash)
|
|
323
|
+
inbox_id = is_a?(Hash) ? self[:id] : id
|
|
324
|
+
return false unless inbox_id && settings_hash.is_a?(Hash)
|
|
325
|
+
|
|
326
|
+
begin
|
|
327
|
+
conn = self.class.create_faraday_connection
|
|
328
|
+
return false unless conn
|
|
329
|
+
|
|
330
|
+
response = conn.put do |req|
|
|
331
|
+
req.url "/api/v1/sharedInboxes/#{inbox_id}/settings"
|
|
332
|
+
req.headers['Content-Type'] = 'application/json'
|
|
333
|
+
req.body = JSON.generate({ settings: settings_hash })
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
if ENV['DEBUG']
|
|
337
|
+
puts "Updating settings for inbox #{inbox_id}"
|
|
338
|
+
puts "Response status: #{response.status}"
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
if [200, 204].include?(response.status)
|
|
342
|
+
puts 'Settings updated successfully' if ENV['DEBUG']
|
|
343
|
+
true
|
|
344
|
+
else
|
|
345
|
+
puts "Error: HTTP #{response.status} - #{response.body}" if ENV['DEBUG']
|
|
346
|
+
false
|
|
347
|
+
end
|
|
348
|
+
rescue StandardError => e
|
|
349
|
+
puts "Error updating settings: #{e.message}" if ENV['DEBUG']
|
|
350
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
351
|
+
false
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def conversations(limit = 20, offset = 0, filter = nil)
|
|
356
|
+
inbox_id = is_a?(Hash) ? self[:id] : id
|
|
357
|
+
return [] unless inbox_id
|
|
358
|
+
|
|
359
|
+
begin
|
|
360
|
+
conn = self.class.create_faraday_connection
|
|
361
|
+
return [] unless conn
|
|
362
|
+
|
|
363
|
+
query = "?limit=#{limit}&offset=#{offset}"
|
|
364
|
+
query += "&filter=#{URI.encode_www_form_component(filter)}" if filter
|
|
365
|
+
|
|
366
|
+
response = conn.get("/api/v1/sharedInboxes/#{inbox_id}/conversations#{query}")
|
|
367
|
+
|
|
368
|
+
if ENV['DEBUG']
|
|
369
|
+
puts "Fetching conversations for inbox #{inbox_id}"
|
|
370
|
+
puts "Response status: #{response.status}"
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
if response.status == 200
|
|
374
|
+
data = JSON.parse(response.body, symbolize_names: true)
|
|
375
|
+
conversations = data[:conversations] || []
|
|
376
|
+
puts "Found #{conversations.count} conversations" if ENV['DEBUG']
|
|
377
|
+
conversations
|
|
378
|
+
else
|
|
379
|
+
puts "Error: HTTP #{response.status} - #{response.body}" if ENV['DEBUG']
|
|
380
|
+
[]
|
|
381
|
+
end
|
|
382
|
+
rescue StandardError => e
|
|
383
|
+
puts "Error fetching conversations: #{e.message}" if ENV['DEBUG']
|
|
384
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
385
|
+
[]
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module FubClient
|
|
2
|
+
class Stage < Resource
|
|
3
|
+
collection_path 'stages'
|
|
4
|
+
root_element :stage
|
|
5
|
+
include_root_in_json true
|
|
6
|
+
|
|
7
|
+
scope :by_pipeline, ->(pipeline_id) { where(pipelineId: pipeline_id) }
|
|
8
|
+
scope :by_type, ->(type) { where(type: type) }
|
|
9
|
+
|
|
10
|
+
def self.active
|
|
11
|
+
where(active: true)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.inactive
|
|
15
|
+
where(active: false)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def deals
|
|
19
|
+
return [] unless id
|
|
20
|
+
|
|
21
|
+
FubClient::Deal.by_stage(id)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def deal_count
|
|
25
|
+
return 0 unless id
|
|
26
|
+
|
|
27
|
+
begin
|
|
28
|
+
response = self.class.get("#{id}/dealCount")
|
|
29
|
+
response[:count] || 0
|
|
30
|
+
rescue StandardError
|
|
31
|
+
0
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def move_to_position(position)
|
|
36
|
+
self.class.put("#{id}/move", { position: position })
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module FubClient
|
|
2
|
+
class Task < Resource
|
|
3
|
+
collection_path 'tasks'
|
|
4
|
+
root_element :task
|
|
5
|
+
include_root_in_json true
|
|
6
|
+
|
|
7
|
+
scope :by_person, ->(person_id) { where(personId: person_id) }
|
|
8
|
+
scope :by_type, ->(type) { where(type: type) }
|
|
9
|
+
scope :by_status, ->(status) { where(status: status) }
|
|
10
|
+
scope :due_before, ->(date) { where(dueBefore: date) }
|
|
11
|
+
scope :due_after, ->(date) { where(dueAfter: date) }
|
|
12
|
+
scope :assigned_to, ->(user_id) { where(assignedTo: user_id) }
|
|
13
|
+
|
|
14
|
+
def self.overdue
|
|
15
|
+
where(status: 'pending').where(dueBefore: Time.now.iso8601)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module FubClient
|
|
2
|
+
class Team < Resource
|
|
3
|
+
collection_path 'teams'
|
|
4
|
+
root_element :team
|
|
5
|
+
include_root_in_json true
|
|
6
|
+
|
|
7
|
+
# Convenience method to find teams by name (partial match)
|
|
8
|
+
scope :by_name, ->(name) { where(q: name) }
|
|
9
|
+
|
|
10
|
+
# Convenience method to find active teams
|
|
11
|
+
def self.active
|
|
12
|
+
where(active: true)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Get users who are members of this team
|
|
16
|
+
def members
|
|
17
|
+
return [] unless id
|
|
18
|
+
|
|
19
|
+
begin
|
|
20
|
+
response = self.class.get("#{id}/members")
|
|
21
|
+
response[:members] || []
|
|
22
|
+
rescue StandardError
|
|
23
|
+
[]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Add a user to this team
|
|
28
|
+
def add_user(user_id, team_leader = false)
|
|
29
|
+
return false unless id && user_id
|
|
30
|
+
|
|
31
|
+
params = { userId: user_id }
|
|
32
|
+
params[:teamLeader] = team_leader if team_leader
|
|
33
|
+
|
|
34
|
+
begin
|
|
35
|
+
self.class.post("#{id}/members", params)
|
|
36
|
+
true
|
|
37
|
+
rescue StandardError
|
|
38
|
+
false
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Remove a user from this team
|
|
43
|
+
def remove_user(user_id)
|
|
44
|
+
return false unless id && user_id
|
|
45
|
+
|
|
46
|
+
begin
|
|
47
|
+
self.class.delete("#{id}/members/#{user_id}")
|
|
48
|
+
true
|
|
49
|
+
rescue StandardError
|
|
50
|
+
false
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Get team statistics
|
|
55
|
+
def stats
|
|
56
|
+
return {} unless id
|
|
57
|
+
|
|
58
|
+
begin
|
|
59
|
+
self.class.get("#{id}/stats")
|
|
60
|
+
rescue StandardError
|
|
61
|
+
{}
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module FubClient
|
|
2
|
+
class TeamInbox < Resource
|
|
3
|
+
collection_path 'teamInboxes'
|
|
4
|
+
root_element :team_inbox
|
|
5
|
+
include_root_in_json true
|
|
6
|
+
|
|
7
|
+
# Get all team inboxes
|
|
8
|
+
def self.all_inboxes
|
|
9
|
+
get('')
|
|
10
|
+
rescue StandardError
|
|
11
|
+
[]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Helper method to get the team associated with this inbox
|
|
15
|
+
def team
|
|
16
|
+
return nil unless respond_to?(:team_id) && team_id
|
|
17
|
+
|
|
18
|
+
FubClient::Team.find(team_id)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Get messages in this team inbox
|
|
22
|
+
def messages(limit = 20, offset = 0)
|
|
23
|
+
return [] unless id
|
|
24
|
+
|
|
25
|
+
begin
|
|
26
|
+
params = {
|
|
27
|
+
limit: limit,
|
|
28
|
+
offset: offset
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
response = self.class.get("#{id}/messages", params)
|
|
32
|
+
response[:messages] || []
|
|
33
|
+
rescue StandardError
|
|
34
|
+
[]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Get participants in a conversation
|
|
39
|
+
def participants(conversation_id)
|
|
40
|
+
return [] unless id && conversation_id
|
|
41
|
+
|
|
42
|
+
begin
|
|
43
|
+
response = self.class.get("#{id}/conversations/#{conversation_id}/participants")
|
|
44
|
+
response[:participants] || []
|
|
45
|
+
rescue StandardError
|
|
46
|
+
[]
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Add a message to a conversation
|
|
51
|
+
def add_message(conversation_id, content, user_id = nil)
|
|
52
|
+
return false unless id && conversation_id && content
|
|
53
|
+
|
|
54
|
+
params = { content: content }
|
|
55
|
+
params[:userId] = user_id if user_id
|
|
56
|
+
|
|
57
|
+
begin
|
|
58
|
+
self.class.post("#{id}/conversations/#{conversation_id}/messages", params)
|
|
59
|
+
true
|
|
60
|
+
rescue StandardError
|
|
61
|
+
false
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module FubClient
|
|
2
|
+
class TextMessage < Resource
|
|
3
|
+
collection_path 'textMessages'
|
|
4
|
+
root_element :text_message
|
|
5
|
+
include_root_in_json true
|
|
6
|
+
|
|
7
|
+
scope :for_person, ->(person_id) { where(personId: person_id) }
|
|
8
|
+
scope :sent_between, lambda { |start_date, end_date|
|
|
9
|
+
where(startDate: start_date, endDate: end_date)
|
|
10
|
+
}
|
|
11
|
+
scope :inbound, -> { where(direction: 'inbound') }
|
|
12
|
+
scope :outbound, -> { where(direction: 'outbound') }
|
|
13
|
+
scope :by_user, ->(user_id) { where(userId: user_id) }
|
|
14
|
+
scope :search, ->(query) { where(q: query) }
|
|
15
|
+
|
|
16
|
+
def self.unread
|
|
17
|
+
where(read: false)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def person
|
|
21
|
+
return nil unless respond_to?(:person_id) && person_id
|
|
22
|
+
|
|
23
|
+
FubClient::Person.find(person_id)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def user
|
|
27
|
+
return nil unless respond_to?(:user_id) && user_id
|
|
28
|
+
|
|
29
|
+
FubClient::User.find(user_id)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.send_message(person_id, message, user_id = nil)
|
|
33
|
+
params = {
|
|
34
|
+
personId: person_id,
|
|
35
|
+
message: message
|
|
36
|
+
}
|
|
37
|
+
params[:userId] = user_id if user_id
|
|
38
|
+
|
|
39
|
+
post('', params)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def mark_as_read
|
|
43
|
+
self.class.put("#{id}/read", {})
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module FubClient
|
|
2
|
+
class TextMessageTemplate < Resource
|
|
3
|
+
collection_path 'textMessageTemplates'
|
|
4
|
+
root_element :text_message_template
|
|
5
|
+
include_root_in_json true
|
|
6
|
+
|
|
7
|
+
# Convenience method to find templates by category
|
|
8
|
+
scope :by_category, ->(category) { where(category: category) }
|
|
9
|
+
|
|
10
|
+
# Convenience method to find active templates
|
|
11
|
+
def self.active
|
|
12
|
+
where(active: true)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Convenience method to find inactive templates
|
|
16
|
+
def self.inactive
|
|
17
|
+
where(active: false)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Merge template with person data
|
|
21
|
+
def merge(person_id)
|
|
22
|
+
return nil unless id && person_id
|
|
23
|
+
|
|
24
|
+
begin
|
|
25
|
+
self.class.post('merge', { id: id, personId: person_id })
|
|
26
|
+
rescue StandardError
|
|
27
|
+
nil
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Send template as a text message to a person
|
|
32
|
+
def send_to(person_id, user_id = nil)
|
|
33
|
+
return false unless id && person_id
|
|
34
|
+
|
|
35
|
+
params = {
|
|
36
|
+
templateId: id,
|
|
37
|
+
personId: person_id
|
|
38
|
+
}
|
|
39
|
+
params[:userId] = user_id if user_id
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
TextMessage.post('', params)
|
|
43
|
+
true
|
|
44
|
+
rescue StandardError
|
|
45
|
+
false
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|