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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +12 -0
  3. data/.gitignore +18 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.tool-versions +1 -0
  8. data/.travis.yml +9 -0
  9. data/CHANGELOG.md +149 -0
  10. data/CODE_OF_CONDUCT.md +49 -0
  11. data/Gemfile +4 -0
  12. data/LICENSE.txt +22 -0
  13. data/README.md +882 -0
  14. data/Rakefile +6 -0
  15. data/bin/console +14 -0
  16. data/bin/setup +8 -0
  17. data/followupboss_client.gemspec +43 -0
  18. data/lib/followupboss_client.rb +16 -0
  19. data/lib/fub_client/action_plan.rb +5 -0
  20. data/lib/fub_client/appointment.rb +42 -0
  21. data/lib/fub_client/appointment_outcome.rb +51 -0
  22. data/lib/fub_client/appointment_type.rb +51 -0
  23. data/lib/fub_client/call.rb +4 -0
  24. data/lib/fub_client/client.rb +200 -0
  25. data/lib/fub_client/compatibility.rb +18 -0
  26. data/lib/fub_client/configuration.rb +54 -0
  27. data/lib/fub_client/cookie_client.rb +190 -0
  28. data/lib/fub_client/custom_field.rb +5 -0
  29. data/lib/fub_client/deal.rb +41 -0
  30. data/lib/fub_client/deal_attachment.rb +61 -0
  31. data/lib/fub_client/deal_custom_field.rb +47 -0
  32. data/lib/fub_client/em_event.rb +5 -0
  33. data/lib/fub_client/email_template.rb +5 -0
  34. data/lib/fub_client/event.rb +8 -0
  35. data/lib/fub_client/group.rb +58 -0
  36. data/lib/fub_client/her_patch.rb +101 -0
  37. data/lib/fub_client/identity.rb +33 -0
  38. data/lib/fub_client/message.rb +41 -0
  39. data/lib/fub_client/middleware/authentication.rb +26 -0
  40. data/lib/fub_client/middleware/cookie_authentication.rb +61 -0
  41. data/lib/fub_client/middleware/parser.rb +59 -0
  42. data/lib/fub_client/middleware.rb +8 -0
  43. data/lib/fub_client/note.rb +4 -0
  44. data/lib/fub_client/people_relationship.rb +34 -0
  45. data/lib/fub_client/person.rb +5 -0
  46. data/lib/fub_client/person_attachment.rb +50 -0
  47. data/lib/fub_client/pipeline.rb +45 -0
  48. data/lib/fub_client/property.rb +26 -0
  49. data/lib/fub_client/rails8_patch.rb +39 -0
  50. data/lib/fub_client/resource.rb +33 -0
  51. data/lib/fub_client/shared_inbox.rb +389 -0
  52. data/lib/fub_client/smart_list.rb +5 -0
  53. data/lib/fub_client/stage.rb +39 -0
  54. data/lib/fub_client/task.rb +18 -0
  55. data/lib/fub_client/team.rb +65 -0
  56. data/lib/fub_client/team_inbox.rb +65 -0
  57. data/lib/fub_client/text_message.rb +46 -0
  58. data/lib/fub_client/text_message_template.rb +49 -0
  59. data/lib/fub_client/user.rb +4 -0
  60. data/lib/fub_client/version.rb +3 -0
  61. data/lib/fub_client/webhook.rb +47 -0
  62. data/lib/fub_client.rb +61 -0
  63. data/scripts/test_api.rb +110 -0
  64. data/scripts/test_shared_inbox.rb +90 -0
  65. metadata +335 -0
@@ -0,0 +1,59 @@
1
+ module FubClient
2
+ module Middleware
3
+ class Parser < Faraday::Middleware
4
+ def initialize(app = nil)
5
+ super(app)
6
+ end
7
+
8
+ def on_complete(env)
9
+ original_json = MultiJson.load(env[:body])
10
+
11
+ # First check if there's an error response
12
+ if original_json.is_a?(Hash) && original_json['errorMessage']
13
+ env[:body] = {
14
+ errors: { message: original_json['errorMessage'] },
15
+ data: nil,
16
+ metadata: nil
17
+ }
18
+ return
19
+ end
20
+
21
+ json = original_json.deep_transform_keys { |k| k.to_s.snakecase.to_sym }
22
+
23
+ # Check if this is an error response in the new format
24
+ if json.is_a?(Hash) && json[:error_message]
25
+ env[:body] = {
26
+ errors: { message: json[:error_message] },
27
+ data: nil,
28
+ metadata: nil
29
+ }
30
+ return
31
+ end
32
+
33
+ metadata = json[:_metadata]
34
+ if metadata.nil?
35
+ result = json
36
+ elsif metadata[:collection].is_a?(String)
37
+ # Make sure the collection key exists and is a string before using it
38
+ collection_key = metadata[:collection].snakecase.to_sym
39
+ result = json[collection_key] || []
40
+ else
41
+ result = []
42
+ end
43
+
44
+ env[:body] = {
45
+ data: result,
46
+ errors: json[:errors],
47
+ metadata: metadata
48
+ }
49
+ rescue StandardError => e
50
+ # Provide a clean error response if JSON parsing fails
51
+ env[:body] = {
52
+ errors: { message: "Parser error: #{e.message}" },
53
+ data: nil,
54
+ metadata: nil
55
+ }
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,8 @@
1
+ require 'fub_client/middleware/authentication'
2
+ require 'fub_client/middleware/cookie_authentication'
3
+ require 'fub_client/middleware/parser'
4
+
5
+ module FubClient
6
+ module Middleware
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ module FubClient
2
+ class Note < Resource
3
+ end
4
+ end
@@ -0,0 +1,34 @@
1
+ module FubClient
2
+ class PeopleRelationship < Resource
3
+ collection_path 'peopleRelationships'
4
+ root_element :people_relationship
5
+ include_root_in_json true
6
+
7
+ scope :for_person, ->(person_id) { where(personId: person_id) }
8
+ scope :with_related_person, ->(related_person_id) { where(relatedPersonId: related_person_id) }
9
+ scope :by_type, ->(type) { where(type: type) }
10
+
11
+ def person
12
+ return nil unless respond_to?(:person_id) && person_id
13
+
14
+ FubClient::Person.find(person_id)
15
+ end
16
+
17
+ def related_person
18
+ return nil unless respond_to?(:related_person_id) && related_person_id
19
+
20
+ FubClient::Person.find(related_person_id)
21
+ end
22
+
23
+ def self.create_relationship(person_id, related_person_id, type, description = nil)
24
+ params = {
25
+ personId: person_id,
26
+ relatedPersonId: related_person_id,
27
+ type: type
28
+ }
29
+ params[:description] = description if description
30
+
31
+ post('', params)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ module FubClient
2
+ class Person < Resource
3
+ collection_path 'people'
4
+ end
5
+ end
@@ -0,0 +1,50 @@
1
+ module FubClient
2
+ class PersonAttachment < Resource
3
+ collection_path 'personAttachments'
4
+ root_element :person_attachment
5
+ include_root_in_json true
6
+
7
+ scope :for_person, ->(person_id) { where(personId: person_id) }
8
+ scope :by_type, ->(type) { where(type: type) }
9
+ scope :by_name, ->(name) { where(q: name) }
10
+
11
+ def person
12
+ return nil unless respond_to?(:person_id) && person_id
13
+
14
+ FubClient::Person.find(person_id)
15
+ end
16
+
17
+ def self.upload(person_id, file_path, name = nil, type = nil, description = nil)
18
+ params = {
19
+ personId: person_id,
20
+ file: File.new(file_path, 'rb')
21
+ }
22
+ params[:name] = name if name
23
+ params[:type] = type if type
24
+ params[:description] = description if description
25
+
26
+ post('', params)
27
+ end
28
+
29
+ def download
30
+ return nil unless id
31
+
32
+ begin
33
+ self.class.get("#{id}/download")
34
+ rescue StandardError
35
+ nil
36
+ end
37
+ end
38
+
39
+ def delete
40
+ return false unless id
41
+
42
+ begin
43
+ self.class.delete(id.to_s)
44
+ true
45
+ rescue StandardError
46
+ false
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,45 @@
1
+ module FubClient
2
+ class Pipeline < Resource
3
+ collection_path 'pipelines'
4
+ root_element :pipeline
5
+ include_root_in_json true
6
+
7
+ def self.active
8
+ where(active: true)
9
+ end
10
+
11
+ def self.inactive
12
+ where(active: false)
13
+ end
14
+
15
+ def stages
16
+ return [] unless id
17
+
18
+ FubClient::Stage.by_pipeline(id)
19
+ end
20
+
21
+ def deals
22
+ return [] unless id
23
+
24
+ FubClient::Deal.where(pipelineId: id)
25
+ end
26
+
27
+ def stats
28
+ return {} unless id
29
+
30
+ begin
31
+ self.class.get("#{id}/stats")
32
+ rescue StandardError
33
+ {}
34
+ end
35
+ end
36
+
37
+ def move_to_position(position)
38
+ self.class.put("#{id}/move", { position: position })
39
+ end
40
+
41
+ def update_stages(stages_data)
42
+ self.class.put("#{id}/stages", { stages: stages_data })
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,26 @@
1
+ module FubClient
2
+ class Property < Resource
3
+ collection_path 'properties'
4
+ root_element :property
5
+ include_root_in_json true
6
+
7
+ scope :search, ->(query) { where(q: query) }
8
+ scope :by_price_range, ->(min, max) { where(minPrice: min, maxPrice: max) }
9
+ scope :by_location, lambda { |city, state = nil, zip = nil|
10
+ params = { city: city }
11
+ params[:state] = state if state
12
+ params[:zip] = zip if zip
13
+ where(params)
14
+ }
15
+ scope :by_features, lambda { |beds = nil, baths = nil, sq_ft = nil|
16
+ params = {}
17
+ params[:beds] = beds if beds
18
+ params[:baths] = baths if baths
19
+ params[:minSqFt] = sq_ft if sq_ft
20
+ where(params)
21
+ }
22
+ scope :for_person, ->(person_id) { where(personId: person_id) }
23
+ scope :active, -> { where(active: true) }
24
+ scope :inactive, -> { where(active: false) }
25
+ end
26
+ end
@@ -0,0 +1,39 @@
1
+ # Rails 8 compatibility patch for Her gem
2
+ # Her gem expects: (ActiveSupport.const_defined?('ProxyObject') ? ActiveSupport::ProxyObject : ActiveSupport::BasicObject)
3
+
4
+ unless defined?(ActiveSupport::ProxyObject)
5
+ begin
6
+ if defined?(ActiveSupport::BasicObject)
7
+ ActiveSupport.const_set('ProxyObject', ActiveSupport::BasicObject)
8
+ puts '[FubClient] Created ActiveSupport::ProxyObject from BasicObject'
9
+ else
10
+ ActiveSupport.const_set('ProxyObject', BasicObject)
11
+ puts "[FubClient] Created ActiveSupport::ProxyObject from Ruby's BasicObject"
12
+ end
13
+ rescue NameError
14
+ ActiveSupport.const_set('ProxyObject', BasicObject)
15
+ puts "[FubClient] Created ActiveSupport::ProxyObject from Ruby's BasicObject (fallback)"
16
+ end
17
+ end
18
+
19
+ begin
20
+ ActiveSupport::BasicObject
21
+ rescue NameError
22
+ if defined?(ActiveSupport::ProxyObject)
23
+ ActiveSupport.const_set('BasicObject', ActiveSupport::ProxyObject)
24
+ puts '[FubClient] Created ActiveSupport::BasicObject from ProxyObject'
25
+ end
26
+ end
27
+
28
+ # Faraday 2.x compatibility
29
+ if defined?(Faraday) && !defined?(Faraday::Response::Middleware)
30
+ Faraday::Response.class_eval do
31
+ class Middleware < Faraday::Middleware
32
+ def initialize(app, options = {})
33
+ super(app)
34
+ @options = options
35
+ end
36
+ end
37
+ end
38
+ puts '[FubClient] Created Faraday::Response::Middleware for Her gem compatibility'
39
+ end
@@ -0,0 +1,33 @@
1
+ module FubClient
2
+ class Resource
3
+ include Her::Model
4
+ use_api FubClient::Client.instance.her_api
5
+
6
+ collection_path '/'
7
+
8
+ def self.safe_all
9
+ result = all
10
+ result.nil? ? [] : result
11
+ rescue StandardError
12
+ []
13
+ end
14
+
15
+ scope :by_page, lambda { |page, per_page|
16
+ where(offset: (page - 1) * per_page, limit: per_page)
17
+ }
18
+
19
+ def self.total
20
+ by_page(1, 1).metadata[:total]
21
+ rescue StandardError
22
+ 0
23
+ end
24
+
25
+ def self.method_missing(method, *args, &blk)
26
+ super
27
+ rescue NoMethodError => e
28
+ return [] if e.message.include?('nil:NilClass') || e.message.include?('for nil:NilClass')
29
+
30
+ raise e
31
+ end
32
+ end
33
+ end