From 33ecaad3c911e419f9bc636d582a06c447349b79 Mon Sep 17 00:00:00 2001 From: Mohamed Ziata Date: Fri, 6 Mar 2020 14:02:09 +0100 Subject: [PATCH 01/47] [bugfix] Missing client in the response of the object created Then you can not use the nested resources. Example: ```ruby contact = INTERCOM_CLIENT.contacts.new(email: "user@example.com") INTERCOM_CLIENT.contacts.save(contact) company = INTERCOM_CLIENT.contacts.new(company_id: "abc-company-example") contact.add_company(id: company.id) # this fails!! ``` --- lib/intercom/api_operations/save.rb | 1 + spec/unit/intercom/contact_spec.rb | 55 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/lib/intercom/api_operations/save.rb b/lib/intercom/api_operations/save.rb index caef1c94..8bab9c05 100644 --- a/lib/intercom/api_operations/save.rb +++ b/lib/intercom/api_operations/save.rb @@ -27,6 +27,7 @@ def save(object) else response = @client.post("/#{collection_name}", object.to_submittable_hash.merge(identity_hash(object))) end + object.client = @client object.from_response(response) if response # may be nil we received back a 202 end diff --git a/spec/unit/intercom/contact_spec.rb b/spec/unit/intercom/contact_spec.rb index 96aab94b..b0193fe4 100644 --- a/spec/unit/intercom/contact_spec.rb +++ b/spec/unit/intercom/contact_spec.rb @@ -311,5 +311,60 @@ client.expects(:delete).with("/contacts/1/companies/#{company.id}", "id": tag.id ).returns(test_company) contact.remove_company({ "id": tag.id }) end + + describe 'just after creating the contact' do + let(:contact) do + contact = Intercom::Contact.new('email' => 'jo@example.com', :external_id => 'i-1224242') + client.expects(:post).with('/contacts', 'email' => 'jo@example.com', 'external_id' => 'i-1224242', 'custom_attributes' => {}) + .returns('id' => 1, 'email' => 'jo@example.com', 'external_id' => 'i-1224242') + client.contacts.save(contact) + end + + it 'returns a collection proxy for listing notes' do + proxy = contact.notes + _(proxy.resource_name).must_equal 'notes' + _(proxy.url).must_equal '/contacts/1/notes' + _(proxy.resource_class).must_equal Intercom::Note + end + + it 'returns a collection proxy for listing tags' do + proxy = contact.tags + _(proxy.resource_name).must_equal 'tags' + _(proxy.url).must_equal '/contacts/1/tags' + _(proxy.resource_class).must_equal Intercom::Tag + end + + it 'returns a collection proxy for listing companies' do + proxy = contact.companies + _(proxy.resource_name).must_equal 'companies' + _(proxy.url).must_equal '/contacts/1/companies' + _(proxy.resource_class).must_equal Intercom::Company + end + + it 'adds a note to a contact' do + client.expects(:post).with('/contacts/1/notes', {body: note.body}).returns(note.to_hash) + contact.create_note({body: note.body}) + end + + it 'adds a tag to a contact' do + client.expects(:post).with('/contacts/1/tags', "id": tag.id).returns(tag.to_hash) + contact.add_tag({ "id": tag.id }) + end + + it 'removes a tag from a contact' do + client.expects(:delete).with("/contacts/1/tags/#{tag.id}", "id": tag.id ).returns(tag.to_hash) + contact.remove_tag({ "id": tag.id }) + end + + it 'adds a contact to a company' do + client.expects(:post).with('/contacts/1/companies', "id": company.id).returns(test_company) + contact.add_company({ "id": tag.id }) + end + + it 'removes a contact from a company' do + client.expects(:delete).with("/contacts/1/companies/#{company.id}", "id": tag.id ).returns(test_company) + contact.remove_company({ "id": tag.id }) + end + end end end From 3035aa7ace65dec4d2211a447760cd61f30b73bb Mon Sep 17 00:00:00 2001 From: Mohamed Ziata Date: Fri, 6 Mar 2020 18:18:52 +0100 Subject: [PATCH 02/47] [feature] Conversation : Add/remove nested resource 'contact' Fixes #515 --- README.md | 25 ++++++++++++++---------- lib/intercom/conversation.rb | 1 + spec/unit/intercom/conversation_spec.rb | 26 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 21118879..da96a59a 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Resources this API supports: https://api.intercom.io/counts https://api.intercom.io/subscriptions https://api.intercom.io/jobs - + ### Examples @@ -99,7 +99,7 @@ contacts = intercom.contacts.search( } ) contacts.each {|c| p c.email} -# For full detail on possible queries, please refer to the API documentation: +# For full detail on possible queries, please refer to the API documentation: # https://developers.intercom.com/intercom-api-reference/reference # Merge a lead into an existing user @@ -191,7 +191,7 @@ intercom.data_attributes.save(attribute) attribute.archived = true intercom.data_attributes.save(attribute) -# Find all customer attributes including archived +# Find all customer attributes including archived customer_attributes_incl_archived = intercom.data_attributes.find_all({"model": "contact", "include_archived": true}) customer_attributes_incl_archived.each { |attr| p attribute.name } ``` @@ -321,7 +321,7 @@ conversation.statistics.time_to_admin_reply conversation.statistics.last_assignment_at # Get information on the sla applied to a conversation -conversation.sla_applied.sla_name +conversation.sla_applied.sla_name # REPLYING TO CONVERSATIONS # User (identified by email) replies with a comment @@ -370,9 +370,9 @@ intercom.conversations.mark_read(conversation.id) intercom.conversations.run_assignment_rules(conversation.id) # Search for conversations -# For full detail on possible queries, please refer to the API documentation: -# https://developers.intercom.com/intercom-api-reference/reference - +# For full detail on possible queries, please refer to the API documentation: +# https://developers.intercom.com/intercom-api-reference/reference + # Search for open conversations sorted by the created_at date conversations = intercom.conversations.search( query: { @@ -386,18 +386,23 @@ conversations = intercom.conversations.search( conversations.each {|c| p c.id} # Tagging for conversations -tag = intercom.tags.find(id: "2") +tag = intercom.tags.find(id: "2") conversation = intercom.conversations.find(id: "1") # An Admin ID is required to add or remove tag on a conversation -admin = intercom.admins.find(id: "1") +admin = intercom.admins.find(id: "1") # Add a tag to a conversation conversation.add_tag(id: tag.id, admin_id: admin.id) # Remove a tag from a conversation conversation.remove_tag(id: tag.id, admin_id: admin.id) - + +# Add a contact to a conversation +conversation.add_contact(admin_id: admin.id, customer: { intercom_user_id: contact.id }) + +# Remove a contact from a conversation +conversation.remove_tag(id: contact.id, admin_id: admin.id) ``` #### Full loading of an embedded entity diff --git a/lib/intercom/conversation.rb b/lib/intercom/conversation.rb index e9edec39..64d7b843 100644 --- a/lib/intercom/conversation.rb +++ b/lib/intercom/conversation.rb @@ -7,5 +7,6 @@ class Conversation include ApiOperations::NestedResource nested_resource_methods :tag, operations: %i[add delete] + nested_resource_methods :contact, operations: %i[add delete], path: :customers end end diff --git a/spec/unit/intercom/conversation_spec.rb b/spec/unit/intercom/conversation_spec.rb index 50a494da..c777bda1 100644 --- a/spec/unit/intercom/conversation_spec.rb +++ b/spec/unit/intercom/conversation_spec.rb @@ -81,5 +81,31 @@ client.expects(:delete).with("/conversations/1/tags/1", { "id": tag.id }).returns(nil) _(proc { conversation.remove_tag({ "id": tag.id }) }).must_raise Intercom::HttpError end + + describe 'contacts' do + let(:response) do + { + customers: [ + { type: test_contact['type'], id: test_contact['id'] } + ] + } + end + + it 'adds a contact to a conversation' do + client.expects(:post) + .with("/conversations/1/customers", + { admin_id: test_admin['id'], customer: { intercom_user_id: test_contact['id'] } }) + .returns(response.to_hash) + conversation.add_contact(admin_id: test_admin['id'], customer: { intercom_user_id: test_contact['id'] }) + end + + it 'removes a contact from a conversation' do + client.expects(:delete) + .with("/conversations/1/customers/aaaaaaaaaaaaaaaaaaaaaaaa", + { id: 'aaaaaaaaaaaaaaaaaaaaaaaa', admin_id: '1234' }) + .returns(response.to_hash) + conversation.remove_contact(id: test_contact['id'], admin_id: test_admin['id']) + end + end end end From 0be174a771338dc9c55416b27eacd07726854567 Mon Sep 17 00:00:00 2001 From: Mohamed Ziata Date: Mon, 9 Mar 2020 13:03:58 +0100 Subject: [PATCH 03/47] [typo] README - Fix typo Co-Authored-By: Matthew Murray --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index da96a59a..09ef9279 100644 --- a/README.md +++ b/README.md @@ -402,7 +402,7 @@ conversation.remove_tag(id: tag.id, admin_id: admin.id) conversation.add_contact(admin_id: admin.id, customer: { intercom_user_id: contact.id }) # Remove a contact from a conversation -conversation.remove_tag(id: contact.id, admin_id: admin.id) +conversation.remove_contact(id: contact.id, admin_id: admin.id) ``` #### Full loading of an embedded entity From 0ec2dbdaf1a02778043d489647b1c2182b96dd5e Mon Sep 17 00:00:00 2001 From: Matthew Murray Date: Tue, 10 Mar 2020 10:15:14 +0000 Subject: [PATCH 04/47] Bump intercom to 4.0.1 --- lib/intercom/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/intercom/version.rb b/lib/intercom/version.rb index 85502869..5f2ea446 100644 --- a/lib/intercom/version.rb +++ b/lib/intercom/version.rb @@ -1,3 +1,3 @@ module Intercom #:nodoc: - VERSION = "4.0.0" + VERSION = "4.0.1" end From 7740007a30fdcceb36d20da9320bc2de5e9c02ad Mon Sep 17 00:00:00 2001 From: Matthew Murray Date: Tue, 10 Mar 2020 10:24:42 +0000 Subject: [PATCH 05/47] Bump version to 4.0.1 --- changes.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/changes.txt b/changes.txt index c6e35cef..1073568c 100644 --- a/changes.txt +++ b/changes.txt @@ -1,4 +1,8 @@ -4.0 +4.0.1 +- Fixed bug with nested resources. +- Support for add/remove contact on conversation object. + +4.0.0 New version to support API version 2.0. - Added support for new Contacts API. - Added support for Conversation Search and for Conversation model changes. From fae9d35ebcbb60015a898f011e20356d466e3af7 Mon Sep 17 00:00:00 2001 From: Rahul D'souza Date: Tue, 14 Jul 2020 18:09:07 +0530 Subject: [PATCH 06/47] Release v4.1.0 (#531) * Articles endpoint SDK support * Collections Endpoint Support (#523) * Sections Endpoint Support (#524) * Added Collections endpoint SDK support * Added test coverage * Added dirty_tracking support for nested objects (#525) * Added support to check for equality of two resources (#527) * Updated README and logged changes for v4.1.0 (#526) --- README.md | 102 +++++++++++++++++- lib/intercom.rb | 6 ++ lib/intercom/article.rb | 7 ++ lib/intercom/client.rb | 12 +++ lib/intercom/collection.rb | 7 ++ lib/intercom/section.rb | 23 ++++ lib/intercom/service/article.rb | 20 ++++ lib/intercom/service/collection.rb | 24 +++++ lib/intercom/service/section.rb | 7 ++ lib/intercom/traits/api_resource.rb | 17 ++- lib/intercom/traits/dirty_tracking.rb | 9 +- spec/spec_helper.rb | 98 +++++++++++++++++ spec/unit/intercom/article_spec.rb | 40 +++++++ spec/unit/intercom/collection_spec.rb | 32 ++++++ spec/unit/intercom/section_spec.rb | 32 ++++++ .../unit/intercom/traits/api_resource_spec.rb | 57 +++++++++- 16 files changed, 488 insertions(+), 5 deletions(-) create mode 100644 lib/intercom/article.rb create mode 100644 lib/intercom/collection.rb create mode 100644 lib/intercom/section.rb create mode 100644 lib/intercom/service/article.rb create mode 100644 lib/intercom/service/collection.rb create mode 100644 lib/intercom/service/section.rb create mode 100644 spec/unit/intercom/article_spec.rb create mode 100644 spec/unit/intercom/collection_spec.rb create mode 100644 spec/unit/intercom/section_spec.rb diff --git a/README.md b/README.md index 09ef9279..59503821 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ intercom = Intercom::Client.new(token: 'my_token') ```ruby # With a versioned app: -intercom = Intercom::Client.new(token: 'my_token', api_version: '2.0') +intercom = Intercom::Client.new(token: 'my_token', api_version: '2.1') ``` If you are building a third party application you can get your access_tokens by [setting-up-oauth](https://developers.intercom.io/page/setting-up-oauth) for Intercom. @@ -61,6 +61,9 @@ Resources this API supports: https://api.intercom.io/counts https://api.intercom.io/subscriptions https://api.intercom.io/jobs + https://api.intercom.io/articles + https://api.intercom.io/help_center/collections + https://api.intercom.io/help_center/sections ### Examples @@ -525,6 +528,103 @@ intercom.subscriptions.delete(subscription) intercom.subscriptions.all ``` +#### Articles +```ruby +# Create an article +article = intercom.articles.create(title: "New Article", author_id: "123456") + +# Create an article with translations +article = intercom.articles.create(title: "New Article", + author_id: "123456", + translated_content: {fr: {title: "Nouvel Article"}, es: {title: "Nuevo artículo"}}) + +# Fetch an article +intercom.articles.find(id: "123456") + +# List all articles +articles = intercom.articles.all +articles.each { |article| p article.title } + +# Update an article +article.title = "Article Updated!" +intercom.articles.save(article) + +# Update an article's existing translation +article.translated_content.en.title = "English Updated!" +intercom.articles.save(article) + +# Update an article by adding a new translation +article.translated_content.es = {title: "Artículo en español"} +intercom.articles.save(article) + +# Delete an article +intercom.articles.delete(article) +``` + +#### Collections +```ruby +# Create a collection +collection = intercom.collections.create(name: "New Collection") + +# Create a collection with translations +collection = intercom.collections.create(name: "New Collection", + translated_content: {fr: {name: "Nouvelle collection"}, es: {name: "Nueva colección"}}) + +# Fetch a collection +intercom.collections.find(id: "123456") + +# List all collections +collections = intercom.collections.all +collections.each { |collection| p collection.name } + +# Update a collection +collection.name = "Collection updated!" +intercom.collections.save(collection) + +# Update a collection's existing translation +collection.translated_content.en.name = "English Updated!" +intercom.collections.save(collection) + +# Update a collection by adding a new translation +collection.translated_content.es = {name: "Colección en español", description: "Descripción en español"} +intercom.collections.save(collection) + +# Delete an collection +intercom.collections.delete(collection) +``` + +#### Sections +```ruby +# Create a section +section = intercom.sections.create(name: "New Section", parent_id: "123456") + +# Create a section with translations +section = intercom.sections.create(name: "New Section", + translated_content: {fr: {name: "Nouvelle section"}, es: {name: "Nueva sección"}}) + +# Fetch a section +intercom.sections.find(id: "123456") + +# List all sections +sections = intercom.sections.all +sections.each { |section| p section.name } + +# Update a section +section.name = "Section updated!" +intercom.sections.save(section) + +# Update a section's existing translation +section.translated_content.en.name = "English Updated!" +intercom.collections.save(section) + +# Update a section by adding a new translation +section.translated_content.es = {name: "Sección en español"} +intercom.collections.save(section) + +# Delete an section +intercom.sections.delete(section) +``` + ### Errors There are different styles for error handling - some people prefer exceptions; some prefer nil and check; some prefer error objects/codes. Balancing these preferences alongside our wish to provide an idiomatic gem has brought us to use the current mechanism of throwing specific exceptions. Our approach in the client is to propagate errors and signal our failure loudly so that erroneous data does not get propagated through our customers' systems - in other words, if you see a `Intercom::ServiceUnavailableError` you know where the problem is. diff --git a/lib/intercom.rb b/lib/intercom.rb index f9587801..b1793064 100644 --- a/lib/intercom.rb +++ b/lib/intercom.rb @@ -2,6 +2,8 @@ require 'intercom/version' require 'intercom/service/admin' +require 'intercom/service/article' +require 'intercom/service/collection' require 'intercom/service/company' require 'intercom/service/contact' require 'intercom/service/conversation' @@ -12,6 +14,7 @@ require 'intercom/service/job' require 'intercom/service/subscription' require 'intercom/service/segment' +require 'intercom/service/section' require 'intercom/service/tag' require 'intercom/service/team' require 'intercom/service/visitor' @@ -24,16 +27,19 @@ require 'intercom/user' require 'intercom/lead' require 'intercom/count' +require 'intercom/collection' require 'intercom/company' require 'intercom/service/data_attribute' require 'intercom/note' require 'intercom/job' require 'intercom/tag' require 'intercom/segment' +require 'intercom/section' require 'intercom/event' require 'intercom/conversation' require 'intercom/message' require 'intercom/admin' +require 'intercom/article' require 'intercom/request' require 'intercom/subscription' require 'intercom/team' diff --git a/lib/intercom/article.rb b/lib/intercom/article.rb new file mode 100644 index 00000000..d1ace3bc --- /dev/null +++ b/lib/intercom/article.rb @@ -0,0 +1,7 @@ +require 'intercom/traits/api_resource' + +module Intercom + class Article + include Traits::ApiResource + end +end diff --git a/lib/intercom/client.rb b/lib/intercom/client.rb index 433c4097..ddc89940 100644 --- a/lib/intercom/client.rb +++ b/lib/intercom/client.rb @@ -48,6 +48,10 @@ def admins Intercom::Service::Admin.new(self) end + def articles + Intercom::Service::Article.new(self) + end + def companies Intercom::Service::Company.new(self) end @@ -84,6 +88,10 @@ def segments Intercom::Service::Segment.new(self) end + def sections + Intercom::Service::Section.new(self) + end + def tags Intercom::Service::Tag.new(self) end @@ -108,6 +116,10 @@ def data_attributes Intercom::Service::DataAttribute.new(self) end + def collections + Intercom::Service::Collection.new(self) + end + def get(path, params) execute_request Intercom::Request.get(path, params) end diff --git a/lib/intercom/collection.rb b/lib/intercom/collection.rb new file mode 100644 index 00000000..3fc7ab26 --- /dev/null +++ b/lib/intercom/collection.rb @@ -0,0 +1,7 @@ +require 'intercom/traits/api_resource' + +module Intercom + class Collection + include Traits::ApiResource + end +end diff --git a/lib/intercom/section.rb b/lib/intercom/section.rb new file mode 100644 index 00000000..75e387ed --- /dev/null +++ b/lib/intercom/section.rb @@ -0,0 +1,23 @@ +require 'intercom/api_operations/list' +require 'intercom/api_operations/find' +require 'intercom/api_operations/save' +require 'intercom/api_operations/delete' + +module Intercom + module Service + class Section < BaseService + include ApiOperations::List + include ApiOperations::Find + include ApiOperations::Save + include ApiOperations::Delete + + def collection_class + Intercom::Section + end + + def collection_name + 'help_center/sections' + end + end + end +end diff --git a/lib/intercom/service/article.rb b/lib/intercom/service/article.rb new file mode 100644 index 00000000..d21bae74 --- /dev/null +++ b/lib/intercom/service/article.rb @@ -0,0 +1,20 @@ +require 'intercom/service/base_service' +require 'intercom/api_operations/find' +require 'intercom/api_operations/list' +require 'intercom/api_operations/delete' +require 'intercom/api_operations/save' + +module Intercom + module Service + class Article < BaseService + include ApiOperations::Find + include ApiOperations::List + include ApiOperations::Delete + include ApiOperations::Save + + def collection_class + Intercom::Article + end + end + end +end diff --git a/lib/intercom/service/collection.rb b/lib/intercom/service/collection.rb new file mode 100644 index 00000000..cbe7a6f2 --- /dev/null +++ b/lib/intercom/service/collection.rb @@ -0,0 +1,24 @@ +require 'intercom/service/base_service' +require 'intercom/api_operations/list' +require 'intercom/api_operations/find' +require 'intercom/api_operations/delete' +require 'intercom/api_operations/save' + +module Intercom + module Service + class Collection < BaseService + include ApiOperations::List + include ApiOperations::Find + include ApiOperations::Delete + include ApiOperations::Save + + def collection_class + Intercom::Collection + end + + def collection_name + "help_center/collections" + end + end + end +end diff --git a/lib/intercom/service/section.rb b/lib/intercom/service/section.rb new file mode 100644 index 00000000..2f03e746 --- /dev/null +++ b/lib/intercom/service/section.rb @@ -0,0 +1,7 @@ +require 'intercom/traits/api_resource' + +module Intercom + class Section + include Traits::ApiResource + end +end diff --git a/lib/intercom/traits/api_resource.rb b/lib/intercom/traits/api_resource.rb index 52707794..8749c196 100644 --- a/lib/intercom/traits/api_resource.rb +++ b/lib/intercom/traits/api_resource.rb @@ -17,6 +17,10 @@ def initialize(attributes = {}) from_hash(attributes) end + def ==(other) + self.class == other.class && to_json == other.to_json + end + def from_response(response) from_hash(response) reset_changed_fields! @@ -37,10 +41,21 @@ def to_hash end end + def to_json(*args) + instance_variables_excluding_dirty_tracking_field.each_with_object({}) do |variable, hash| + next if variable == :@client + + value = instance_variable_get(variable) + hash[variable.to_s.delete('@')] = value.respond_to?(:to_json) ? value.to_json(*args) : value + end + end + def to_submittable_hash submittable_hash = {} to_hash.each do |attribute, value| - submittable_hash[attribute] = value if submittable_attribute?(attribute, value) + next unless submittable_attribute?(attribute, value) + + submittable_hash[attribute] = value.respond_to?(:to_submittable_hash) ? value.to_submittable_hash : value end submittable_hash end diff --git a/lib/intercom/traits/dirty_tracking.rb b/lib/intercom/traits/dirty_tracking.rb index 0d120094..d155c2d9 100644 --- a/lib/intercom/traits/dirty_tracking.rb +++ b/lib/intercom/traits/dirty_tracking.rb @@ -22,7 +22,14 @@ def mark_field_as_changed!(field_name) def field_changed?(field_name) @changed_fields ||= Set.new - @changed_fields.include?(field_name.to_s) + field = instance_variable_get("@#{field_name}") + if field.respond_to?(:field_changed?) + field.to_hash.any? do |attribute, _| + field.field_changed?(attribute) + end + else + @changed_fields.include?(field_name.to_s) + end end def instance_variables_excluding_dirty_tracking_field diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ea084a15..d94db57d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -8,6 +8,32 @@ require 'pry' include WebMock::API +def test_article + { + "id": "1", + "type": "article", + "workspace_id": "tx2p130c", + "title": "new title", + "description": "test Finished articles are visible when they're added to a Help Center collection", + "body": "

thingbop

", + "author_id": 1, + "state": "draft" + } +end + +def test_updated_article + { + "id": "1", + "type": "article", + "workspace_id": "tx2p130c", + "title": "new updated title", + "description": "test Finished articles are visible when they're added to a Help Center collection", + "body": "

thingbop

", + "author_id": 1, + "state": "draft" + } +end + def test_user(email = 'bob@example.com') { 'type' => 'user', @@ -131,6 +157,41 @@ def test_contact(email = 'bob@example.com', role = 'user') } end +def test_collection + { + 'id' => '1', + 'workspace_id' => 'tx2p130c', + 'name' => 'Collection 1', + 'url' => 'http://www.intercom.test/help/', + 'order' => 1, + 'type' => 'collection', + 'description' => 'Collection desc', + 'icon' => 'book-bookmark' + } +end + +def test_collection_list + { + 'type' => 'list', + 'total_count' => 1, + 'pages' => { + 'page' => 1, + 'per_page' => 20, + 'total_pages' => 1 + }, + 'data' => [{ + 'id' => '1', + 'workspace_id' => 'tx2p130c', + 'name' => 'Collection 1', + 'url' => 'http://www.intercom.test/help/', + 'order' => 1, + 'type' => 'collection', + 'description' => 'Collection desc', + 'icon' => 'book-bookmark' + }] + } +end + def test_visitor { 'type' => 'visitor', @@ -789,6 +850,43 @@ def test_app_count } end +def test_section + { + 'id' => '18', + 'workspace_id' => 'tx2p130c', + 'name' => 'Section 1', + 'url' => 'http://www.intercom.test/help/', + 'order' => 0, + 'created_at' => 1_589_801_953, + 'updated_at' => 1_589_801_953, + 'type' => 'section', + 'parent_id' => 1 + } +end + +def test_section_list + { + 'type' => 'list', + 'total_count' => 1, + 'pages' => { + 'page' => 1, + 'per_page' => 20, + 'total_pages' => 1 + }, + 'data' => [{ + 'id' => '18', + 'workspace_id' => 'tx2p130c', + 'name' => 'Section 1', + 'url' => 'http://www.intercom.test/help/', + 'order' => 0, + 'created_at' => 1_589_801_953, + 'updated_at' => 1_589_801_953, + 'type' => 'section', + 'parent_id' => 1 + }] + } +end + def test_segment_count { 'type' => 'count', diff --git a/spec/unit/intercom/article_spec.rb b/spec/unit/intercom/article_spec.rb new file mode 100644 index 00000000..9fa3a695 --- /dev/null +++ b/spec/unit/intercom/article_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe "Intercom::Article" do + let(:client) { Intercom::Client.new(token: 'token') } + + describe "Getting an Article" do + it "successfully finds an article" do + client.expects(:get).with("/articles/1", {}).returns(test_article) + client.articles.find(id: "1") + end + end + + describe "Creating an Article" do + it "successfully creates and article with information passed individually" do + client.expects(:post).with("/articles", {"title" => "new title", "author_id" => 1, "body" => "

thingbop

", "state" => "draft"}).returns(test_article) + client.articles.create(:title => "new title", :author_id => 1, :body => "

thingbop

", :state => "draft") + end + + it "successfully creates and article with information in json" do + client.expects(:post).with("/articles", {"title" => "new title", "author_id" => 1, "body" => "

thingbop

", "state" => "draft"}).returns(test_article) + client.articles.create({title: "new title", author_id: 1, body: "

thingbop

", state: "draft"}) + end + end + + describe "Updating an article" do + it "successfully updates an article" do + article = Intercom::Article.new(id: 12345) + client.expects(:put).with('/articles/12345', {}) + client.articles.save(article) + end + end + + describe "Deleting an article" do + it "successfully deletes an article" do + article = Intercom::Article.new(id: 12345) + client.expects(:delete).with('/articles/12345', {}) + client.articles.delete(article) + end + end +end \ No newline at end of file diff --git a/spec/unit/intercom/collection_spec.rb b/spec/unit/intercom/collection_spec.rb new file mode 100644 index 00000000..87388c9c --- /dev/null +++ b/spec/unit/intercom/collection_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe Intercom::Collection do + let(:client) { Intercom::Client.new(token: 'token') } + + it 'creates a collection' do + client.expects(:post).with('/help_center/collections', { 'name' => 'Collection 1', 'description' => 'Collection desc' }).returns(test_collection) + client.collections.create(:name => 'Collection 1', :description => 'Collection desc') + end + + it 'lists collections' do + client.expects(:get).with('/help_center/collections', {}).returns(test_collection_list) + client.collections.all.each { |t| } + end + + it 'finds a collection' do + client.expects(:get).with('/help_center/collections/1', {}).returns(test_collection) + client.collections.find(id: '1') + end + + it 'updates a collection' do + collection = Intercom::Collection.new(id: '12345') + client.expects(:put).with('/help_center/collections/12345', {}) + client.collections.save(collection) + end + + it 'deletes a collection' do + collection = Intercom::Collection.new(id: '12345') + client.expects(:delete).with('/help_center/collections/12345', {}) + client.collections.delete(collection) + end +end \ No newline at end of file diff --git a/spec/unit/intercom/section_spec.rb b/spec/unit/intercom/section_spec.rb new file mode 100644 index 00000000..ff73f672 --- /dev/null +++ b/spec/unit/intercom/section_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe Intercom::Section do + let(:client) { Intercom::Client.new(token: 'token') } + + it 'creates a section' do + client.expects(:post).with('/help_center/sections', { 'name' => 'Section 1', 'parent_id' => '1' }).returns(test_section) + client.sections.create(:name => 'Section 1', :parent_id => '1') + end + + it 'lists sections' do + client.expects(:get).with('/help_center/sections', {}).returns(test_section_list) + client.sections.all.each { |t| } + end + + it 'finds a section' do + client.expects(:get).with('/help_center/sections/1', {}).returns(test_section) + client.sections.find(id: '1') + end + + it 'updates a section' do + section = Intercom::Section.new(id: '12345') + client.expects(:put).with('/help_center/sections/12345', {}) + client.sections.save(section) + end + + it 'deletes a section' do + section = Intercom::Section.new(id: '12345') + client.expects(:delete).with('/help_center/sections/12345', {}) + client.sections.delete(section) + end +end \ No newline at end of file diff --git a/spec/unit/intercom/traits/api_resource_spec.rb b/spec/unit/intercom/traits/api_resource_spec.rb index b5724556..7afc144f 100644 --- a/spec/unit/intercom/traits/api_resource_spec.rb +++ b/spec/unit/intercom/traits/api_resource_spec.rb @@ -17,7 +17,15 @@ 'metadata' => { 'type' => 'user', 'color' => 'cyan' - } } + }, + 'nested_fields' => { + 'type' => 'nested_fields_content', + 'field_1' => { + 'type' => 'field_content', + 'name' => 'Nested Field' + } + } + } end let(:object_hash) do @@ -35,6 +43,13 @@ metadata: { type: 'user', color: 'cyan' + }, + nested_fields: { + type: 'nested_fields_content', + field_1: { + type: 'field_content', + name: 'Nested Field' + } } } end @@ -107,12 +122,50 @@ class ConcreteApiResource; include Intercom::Traits::ApiResource; end api_resource.from_hash(object_hash) initialized_api_resource = ConcreteApiResource.new(object_hash) - except(object_json, 'type').keys.each do |attribute| assert_equal initialized_api_resource.send(attribute), api_resource.send(attribute) end end + describe 'correctly equates two resources' do + class DummyResource; include Intercom::Traits::ApiResource; end + + specify 'if each resource has the same class and same value' do + api_resource1 = DummyResource.new(object_json) + api_resource2 = DummyResource.new(object_json) + assert_equal (api_resource1 == api_resource2), true + end + + specify 'if each resource has the same class and different value' do + object2_json = object_json.merge('id' => 'bbbbbb') + api_resource1 = DummyResource.new(object_json) + api_resource2 = DummyResource.new(object2_json) + assert_equal (api_resource1 == api_resource2), false + end + + specify 'if each resource has a different class' do + dummy_resource = DummyResource.new(object_json) + assert_equal (dummy_resource == api_resource), false + end + end + + it 'correctly generates submittable hash when no updates' do + assert_equal api_resource.to_submittable_hash, {} + end + + it 'correctly generates submittable hash when there are updates' do + api_resource.name = 'SuperSuite updated' + api_resource.nested_fields.field_1.name = 'Updated Name' + assert_equal api_resource.to_submittable_hash, { + 'name' => 'SuperSuite updated', + 'nested_fields' => { + 'field_1' => { + 'name' => 'Updated Name' + } + } + } + end + def except(h, *keys) keys.each { |key| h.delete(key) } h From f4413b9b881504f0790305c60a0e72f9fe51fa3c Mon Sep 17 00:00:00 2001 From: Rahul D'souza Date: Tue, 14 Jul 2020 18:46:05 +0530 Subject: [PATCH 07/47] Bump intercom to 4.1.0 (#534) --- README.md | 2 +- changes.txt | 7 +++++++ lib/intercom/version.rb | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 59503821..6f21c67f 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ This version of the gem is compatible with `Ruby 2.1` and above. Using bundler: - gem 'intercom', '~> 4.0' + gem 'intercom', '~> 4.1' ## Basic Usage diff --git a/changes.txt b/changes.txt index 1073568c..03d56f0e 100644 --- a/changes.txt +++ b/changes.txt @@ -1,3 +1,10 @@ +4.1.0 +- Added support for new Articles API. +- Added support for new Collections API. +- Added support for new Sections API. +- Added support to equate two resources. +- Fixed issue for dirty tracking nested typed objects. + 4.0.1 - Fixed bug with nested resources. - Support for add/remove contact on conversation object. diff --git a/lib/intercom/version.rb b/lib/intercom/version.rb index 5f2ea446..a831c139 100644 --- a/lib/intercom/version.rb +++ b/lib/intercom/version.rb @@ -1,3 +1,3 @@ module Intercom #:nodoc: - VERSION = "4.0.1" + VERSION = "4.1.0" end From 60bcb5c7d09db9d103f17ed87cbb5b95becbb36b Mon Sep 17 00:00:00 2001 From: theandrewykim Date: Thu, 16 Jul 2020 20:11:20 -0400 Subject: [PATCH 08/47] update readme to show untag company action --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 6f21c67f..4354deb9 100644 --- a/README.md +++ b/README.md @@ -261,6 +261,9 @@ intercom.tags.all.map {|tag| tag.name } # Tag companies tag = intercom.tags.tag(name: 'blue', companies: [{company_id: "42ea2f1b93891f6a99000427"}]) + +# Untag Companies +tag = intercom.tags.untag(name: 'blue', companies: [{ company_id: "42ea2f1b93891f6a99000427" }]) ``` #### Notes From e855241f5f779dad368aa7805c94a73c74789f0c Mon Sep 17 00:00:00 2001 From: Matthew Murray Date: Tue, 11 Aug 2020 16:43:35 +0100 Subject: [PATCH 09/47] Add leads method to client --- lib/intercom/client.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/intercom/client.rb b/lib/intercom/client.rb index ddc89940..883a99ae 100644 --- a/lib/intercom/client.rb +++ b/lib/intercom/client.rb @@ -104,6 +104,10 @@ def users Intercom::Service::User.new(self) end + def leads + Intercom::Service::Lead.new(self) + end + def visitors Intercom::Service::Visitor.new(self) end From 114fcf78b643db6dac48b05279d666c21edafac0 Mon Sep 17 00:00:00 2001 From: Matthew Murray Date: Tue, 11 Aug 2020 16:52:07 +0100 Subject: [PATCH 10/47] Bump intercom to 4.1.1 --- lib/intercom/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/intercom/version.rb b/lib/intercom/version.rb index a831c139..9ea75368 100644 --- a/lib/intercom/version.rb +++ b/lib/intercom/version.rb @@ -1,3 +1,3 @@ module Intercom #:nodoc: - VERSION = "4.1.0" + VERSION = "4.1.1" end From 1d335c0087d617e61eabe69b931df75989aef4db Mon Sep 17 00:00:00 2001 From: Matthew Murray Date: Tue, 11 Aug 2020 16:56:04 +0100 Subject: [PATCH 11/47] Bump version to 4.1.1 --- changes.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changes.txt b/changes.txt index 03d56f0e..e2960ea4 100644 --- a/changes.txt +++ b/changes.txt @@ -1,3 +1,6 @@ +4.1.1 +- Fixed bug with deprecated lead resource. + 4.1.0 - Added support for new Articles API. - Added support for new Collections API. From a12d7c92f3bc972e4893d1ceffb224c372b54fda Mon Sep 17 00:00:00 2001 From: theandrewykim Date: Wed, 30 Sep 2020 15:13:15 -0500 Subject: [PATCH 12/47] refactor error handling --- lib/intercom/request.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/intercom/request.rb b/lib/intercom/request.rb index 0be75505..9caf9e45 100644 --- a/lib/intercom/request.rb +++ b/lib/intercom/request.rb @@ -158,13 +158,7 @@ def execute(target_base_url = nil, token:, read_timeout: 90, open_timeout: 30, a private def raise_errors_on_failure(res) code = res.code.to_i - if code == 404 - raise Intercom::ResourceNotFound, 'Resource Not Found' - elsif code == 401 - raise Intercom::AuthenticationError, 'Unauthorized' - elsif code == 403 - raise Intercom::AuthenticationError, 'Forbidden' - elsif code == 429 + if code ==429 raise Intercom::RateLimitExceeded, 'Rate Limit Exceeded' elsif code == 500 raise Intercom::ServerError, 'Server Error' From 4f683c07c9a6411f1a791acddb9cd8f4a5010b68 Mon Sep 17 00:00:00 2001 From: theandrewykim Date: Wed, 30 Sep 2020 15:15:08 -0500 Subject: [PATCH 13/47] add space --- lib/intercom/request.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/intercom/request.rb b/lib/intercom/request.rb index 9caf9e45..481f1b1e 100644 --- a/lib/intercom/request.rb +++ b/lib/intercom/request.rb @@ -158,7 +158,7 @@ def execute(target_base_url = nil, token:, read_timeout: 90, open_timeout: 30, a private def raise_errors_on_failure(res) code = res.code.to_i - if code ==429 + if code == 429 raise Intercom::RateLimitExceeded, 'Rate Limit Exceeded' elsif code == 500 raise Intercom::ServerError, 'Server Error' From 08ded8bfaa31ce30382321e56addb236208c831a Mon Sep 17 00:00:00 2001 From: Clayton Passmore Date: Mon, 19 Oct 2020 19:10:32 +0000 Subject: [PATCH 14/47] Allow companies to be deleted --- lib/intercom/service/company.rb | 2 ++ spec/unit/intercom/company_spec.rb | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/lib/intercom/service/company.rb b/lib/intercom/service/company.rb index f23a97c6..b627c452 100644 --- a/lib/intercom/service/company.rb +++ b/lib/intercom/service/company.rb @@ -1,4 +1,5 @@ require 'intercom/service/base_service' +require 'intercom/api_operations/delete' require 'intercom/api_operations/list' require 'intercom/api_operations/scroll' require 'intercom/api_operations/find' @@ -11,6 +12,7 @@ module Intercom module Service class Company < BaseService + include ApiOperations::Delete include ApiOperations::Find include ApiOperations::FindAll include ApiOperations::Load diff --git a/spec/unit/intercom/company_spec.rb b/spec/unit/intercom/company_spec.rb index c7e1c646..9bced631 100644 --- a/spec/unit/intercom/company_spec.rb +++ b/spec/unit/intercom/company_spec.rb @@ -35,4 +35,10 @@ _(proxy.url).must_equal '/companies/1/contacts' _(proxy.resource_class).must_equal Intercom::Contact end + + it "deletes a company" do + company = Intercom::Company.new("id" => "1") + client.expects(:delete).with("/companies/1", {}).returns(test_company) + client.companies.delete(company) + end end From bb23014ed63b606f9c69c8903e6755d55f0b8e67 Mon Sep 17 00:00:00 2001 From: Rahul D'souza Date: Thu, 29 Oct 2020 07:50:35 +0530 Subject: [PATCH 15/47] Add empty hash as payload for run assignment rules (#555) --- lib/intercom/service/conversation.rb | 2 +- spec/unit/intercom/conversation_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/intercom/service/conversation.rb b/lib/intercom/service/conversation.rb index bed5e93b..2a8d8ee4 100644 --- a/lib/intercom/service/conversation.rb +++ b/lib/intercom/service/conversation.rb @@ -58,7 +58,7 @@ def assign(reply_data) def run_assignment_rules(id) collection_name = Utils.resource_class_to_collection_name(collection_class) - response = @client.post("/#{collection_name}/#{id}/run_assignment_rules") + response = @client.post("/#{collection_name}/#{id}/run_assignment_rules", {}) collection_class.new.from_response(response) end end diff --git a/spec/unit/intercom/conversation_spec.rb b/spec/unit/intercom/conversation_spec.rb index c777bda1..79919d54 100644 --- a/spec/unit/intercom/conversation_spec.rb +++ b/spec/unit/intercom/conversation_spec.rb @@ -54,7 +54,7 @@ end it 'runs assignment rules on a conversation' do - client.expects(:post).with('/conversations/147/run_assignment_rules').returns(test_conversation) + client.expects(:post).with('/conversations/147/run_assignment_rules', {}).returns(test_conversation) client.conversations.run_assignment_rules('147') end From b62b5fd587c4ce8d3b0efbaa3a901e820fa829d7 Mon Sep 17 00:00:00 2001 From: Clayton Passmore Date: Wed, 28 Oct 2020 23:05:35 -0400 Subject: [PATCH 16/47] Update spec/unit/intercom/company_spec.rb Co-authored-by: Rahul D'souza --- spec/unit/intercom/company_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/unit/intercom/company_spec.rb b/spec/unit/intercom/company_spec.rb index 9bced631..03fe762b 100644 --- a/spec/unit/intercom/company_spec.rb +++ b/spec/unit/intercom/company_spec.rb @@ -38,7 +38,7 @@ it "deletes a company" do company = Intercom::Company.new("id" => "1") - client.expects(:delete).with("/companies/1", {}).returns(test_company) + client.expects(:delete).with("/companies/1", {}) client.companies.delete(company) end end From 1aa86b04698a497aeea2f580c3ed1a9fa3539b1d Mon Sep 17 00:00:00 2001 From: Rahul D'souza Date: Thu, 29 Oct 2020 20:09:27 +0530 Subject: [PATCH 17/47] Fixed issue with scroll collection proxy (#556) --- lib/intercom/scroll_collection_proxy.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/intercom/scroll_collection_proxy.rb b/lib/intercom/scroll_collection_proxy.rb index 929c1425..48129b3b 100644 --- a/lib/intercom/scroll_collection_proxy.rb +++ b/lib/intercom/scroll_collection_proxy.rb @@ -26,7 +26,7 @@ def next(scroll_parameter = nil) raise Intercom::HttpError, 'Http Error - No response entity returned' unless response_hash @scroll_param = extract_scroll_param(response_hash) - top_level_entity_key = deserialize_response_hash(response_hash) + top_level_entity_key = entity_key_from_response(response_hash) response_hash[top_level_entity_key] = response_hash[top_level_entity_key].map do |object_json| Lib::TypedJsonDeserializer.new(object_json, @client).deserialize end @@ -44,7 +44,8 @@ def each(&block) end raise Intercom::HttpError, 'Http Error - No response entity returned' unless response_hash - response_hash[deserialize_response_hash(response_hash)].each do |object_json| + top_level_entity_key = entity_key_from_response(response_hash) + response_hash[top_level_entity_key].each do |object_json| block.call Lib::TypedJsonDeserializer.new(object_json, @client).deserialize end scroll_param = extract_scroll_param(response_hash) @@ -55,8 +56,8 @@ def each(&block) private - def deserialize_response_hash(response_hash) - top_level_type = response_hash.delete('type') + def entity_key_from_response(response_hash) + top_level_type = response_hash['type'] if resource_name == 'subscriptions' 'items' else @@ -65,7 +66,7 @@ def deserialize_response_hash(response_hash) end def records_present?(response_hash) - !response_hash[@resource_name].empty? + !response_hash[entity_key_from_response(response_hash)].empty? end def extract_scroll_param(response_hash) From a1bbff4afcd8939f85f45560ee14b17dbef27a2d Mon Sep 17 00:00:00 2001 From: Markus Muehlberger <1052277+mmuehlberger@users.noreply.github.com> Date: Fri, 30 Oct 2020 12:30:17 +0000 Subject: [PATCH 18/47] Add ability to archive/unarchive contacts (#551) Co-authored-by: Markus Muehlberger --- lib/intercom/service/contact.rb | 10 ++++++++++ spec/unit/intercom/contact_spec.rb | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/intercom/service/contact.rb b/lib/intercom/service/contact.rb index 737dc96e..7b8b7504 100644 --- a/lib/intercom/service/contact.rb +++ b/lib/intercom/service/contact.rb @@ -33,6 +33,16 @@ def merge(lead, user) user.from_response(response) end + def archive(contact) + @client.post("/#{collection_name}/#{contact.id}/archive", {}) + contact + end + + def unarchive(contact) + @client.post("/#{collection_name}/#{contact.id}/unarchive", {}) + contact + end + private def raise_invalid_merge_error raise Intercom::InvalidMergeError, 'Merging can only be performed on a lead into a user' end diff --git a/spec/unit/intercom/contact_spec.rb b/spec/unit/intercom/contact_spec.rb index b0193fe4..79fc185b 100644 --- a/spec/unit/intercom/contact_spec.rb +++ b/spec/unit/intercom/contact_spec.rb @@ -248,6 +248,18 @@ client.contacts.delete(contact) end + it 'archives a contact' do + contact = Intercom::Contact.new('id' => '1') + client.expects(:post).with('/contacts/1/archive', {}) + client.contacts.archive(contact) + end + + it 'unarchives a contact' do + contact = Intercom::Contact.new('id' => '1') + client.expects(:post).with('/contacts/1/unarchive', {}) + client.contacts.unarchive(contact) + end + describe 'merging' do let(:lead) { Intercom::Contact.from_api(external_id: 'contact_id', role: 'lead') } let(:user) { Intercom::Contact.from_api(id: 'external_id', role: 'user') } From c62d7006a55c8bcef9f5f79980223018206ea0f8 Mon Sep 17 00:00:00 2001 From: Rahul D'souza Date: Fri, 30 Oct 2020 18:10:14 +0530 Subject: [PATCH 19/47] Revert "refactor error handling" (#558) --- lib/intercom/request.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/intercom/request.rb b/lib/intercom/request.rb index 481f1b1e..0be75505 100644 --- a/lib/intercom/request.rb +++ b/lib/intercom/request.rb @@ -158,7 +158,13 @@ def execute(target_base_url = nil, token:, read_timeout: 90, open_timeout: 30, a private def raise_errors_on_failure(res) code = res.code.to_i - if code == 429 + if code == 404 + raise Intercom::ResourceNotFound, 'Resource Not Found' + elsif code == 401 + raise Intercom::AuthenticationError, 'Unauthorized' + elsif code == 403 + raise Intercom::AuthenticationError, 'Forbidden' + elsif code == 429 raise Intercom::RateLimitExceeded, 'Rate Limit Exceeded' elsif code == 500 raise Intercom::ServerError, 'Server Error' From bab09db1e52d91191f3baeab23f01cbb8176a1ba Mon Sep 17 00:00:00 2001 From: Rahul D'souza Date: Fri, 30 Oct 2020 18:17:06 +0530 Subject: [PATCH 20/47] Add support for listing contact segments (#557) --- README.md | 3 +++ lib/intercom/contact.rb | 1 + lib/intercom/segment.rb | 4 ++++ spec/unit/intercom/contact_spec.rb | 7 +++++++ 4 files changed, 15 insertions(+) diff --git a/README.md b/README.md index 4354deb9..ce3d84e3 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,9 @@ contact.create_note(body: "

Text for the note

") # List notes for a contact contact.notes.each {|n| p n.body} +# List segments for a contact +contact.segments.each {|segment| p segment.name} + # Add a contact to a company company = intercom.companies.find(id: "123") contact.add_company(id: company.id) diff --git a/lib/intercom/contact.rb b/lib/intercom/contact.rb index 487b5b0f..f5332ab5 100644 --- a/lib/intercom/contact.rb +++ b/lib/intercom/contact.rb @@ -13,6 +13,7 @@ class Contact nested_resource_methods :tag, operations: %i[add delete list] nested_resource_methods :note, operations: %i[create list] nested_resource_methods :company, operations: %i[add delete list] + nested_resource_methods :segment, operations: %i[list] def self.collection_proxy_class Intercom::BaseCollectionProxy diff --git a/lib/intercom/segment.rb b/lib/intercom/segment.rb index 88de03d9..589ae474 100644 --- a/lib/intercom/segment.rb +++ b/lib/intercom/segment.rb @@ -3,5 +3,9 @@ module Intercom class Segment include Traits::ApiResource + + def self.collection_proxy_class + Intercom::BaseCollectionProxy + end end end diff --git a/spec/unit/intercom/contact_spec.rb b/spec/unit/intercom/contact_spec.rb index 79fc185b..aca5f935 100644 --- a/spec/unit/intercom/contact_spec.rb +++ b/spec/unit/intercom/contact_spec.rb @@ -285,6 +285,13 @@ _(proxy.resource_class).must_equal Intercom::Note end + it 'returns a collection proxy for listing segments' do + proxy = contact.segments + _(proxy.resource_name).must_equal 'segments' + _(proxy.url).must_equal '/contacts/1/segments' + _(proxy.resource_class).must_equal Intercom::Segment + end + it 'returns a collection proxy for listing tags' do proxy = contact.tags _(proxy.resource_name).must_equal 'tags' From 215c97e9225867631d534a13e08873437980221a Mon Sep 17 00:00:00 2001 From: Rahul D'souza Date: Fri, 30 Oct 2020 18:43:54 +0530 Subject: [PATCH 21/47] Readme updates (#559) --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index ce3d84e3..c30b4b40 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,12 @@ intercom.contacts.save(contact) contact.role = "user" intercom.contacts.save(contact) +# Archive a contact +intercom.contacts.archive(contact) + +# Unarchive a contact +intercom.contacts.unarchive(contact) + # Delete a contact permanently intercom.contacts.delete(contact) @@ -169,6 +175,9 @@ company = intercom.companies.find(id: "41e66f0313708347cb0000d0") company.name = 'Updated company name' intercom.companies.save(company) +# Delete a company +intercom.companies.delete(company) + # Iterate over all companies intercom.companies.all.each {|company| puts %Q(#{company.name} - #{company.custom_attributes["referral_source"]}) } intercom.companies.all.map {|company| company.name } From 93d18bf3722ae7e3ec82a86a50a612d039dd6fc5 Mon Sep 17 00:00:00 2001 From: Rahul D'souza Date: Fri, 30 Oct 2020 19:56:34 +0530 Subject: [PATCH 22/47] Bump version to 4.1.2 (#560) --- README.md | 2 +- changes.txt | 7 +++++++ lib/intercom/version.rb | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c30b4b40..bc9f24b8 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ intercom = Intercom::Client.new(token: 'my_token') ```ruby # With a versioned app: -intercom = Intercom::Client.new(token: 'my_token', api_version: '2.1') +intercom = Intercom::Client.new(token: 'my_token', api_version: '2.2') ``` If you are building a third party application you can get your access_tokens by [setting-up-oauth](https://developers.intercom.io/page/setting-up-oauth) for Intercom. diff --git a/changes.txt b/changes.txt index e2960ea4..08991b76 100644 --- a/changes.txt +++ b/changes.txt @@ -1,3 +1,10 @@ +4.1.2 +- Adding support for company delete. +- Adding support for archiving/unarchiving contacts. +- Adding support for listing contact segments. +- Fixed issue with scroll collection proxy. +- Fixed issue with running assignment rules on a conversation. + 4.1.1 - Fixed bug with deprecated lead resource. diff --git a/lib/intercom/version.rb b/lib/intercom/version.rb index 9ea75368..df41bd76 100644 --- a/lib/intercom/version.rb +++ b/lib/intercom/version.rb @@ -1,3 +1,3 @@ module Intercom #:nodoc: - VERSION = "4.1.1" + VERSION = "4.1.2" end From 50db6c1a6f4a9c3215ae7bd1a54d49aa4154a855 Mon Sep 17 00:00:00 2001 From: Finn Lawrence Date: Wed, 20 Jan 2021 12:21:21 +1300 Subject: [PATCH 23/47] Update Readme with correct commands for running spec --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bc9f24b8..056de4d3 100644 --- a/README.md +++ b/README.md @@ -700,13 +700,13 @@ intercom = Intercom::Client.new(token: ENV['AT'], handle_rate_limit: true) ```bash # all tests -bundle exec spec +bundle exec rake spec # unit tests -bundle exec spec:unit +bundle exec rake spec:unit # integration tests -bundle exec spec:integration +bundle exec rake spec:integration # single test file bundle exec m spec/unit/intercom/job_spec.rb From 9bd034d9f1e7ef84105765712115ce84f23cab16 Mon Sep 17 00:00:00 2001 From: Finn Lawrence Date: Wed, 20 Jan 2021 13:01:56 +1300 Subject: [PATCH 24/47] Move dynamic accessors to instance rather than class --- lib/intercom/lib/dynamic_accessors.rb | 19 +++++++++---------- spec/unit/intercom/contact_spec.rb | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/lib/intercom/lib/dynamic_accessors.rb b/lib/intercom/lib/dynamic_accessors.rb index 1b053d2e..9d26b4fc 100644 --- a/lib/intercom/lib/dynamic_accessors.rb +++ b/lib/intercom/lib/dynamic_accessors.rb @@ -5,20 +5,19 @@ module DynamicAccessors class << self def define_accessors(attribute, value, object) - klass = object.class if attribute.to_s.end_with?('_at') && attribute.to_s != 'update_last_request_at' - define_date_based_accessors(attribute, value, klass) + define_date_based_accessors(attribute, value, object) elsif object.flat_store_attribute?(attribute) - define_flat_store_based_accessors(attribute, value, klass) + define_flat_store_based_accessors(attribute, value, object) else - define_standard_accessors(attribute, value, klass) + define_standard_accessors(attribute, value, object) end end private - def define_flat_store_based_accessors(attribute, value, klass) - klass.class_eval %Q" + def define_flat_store_based_accessors(attribute, value, object) + object.instance_eval %Q" def #{attribute}=(value) mark_field_as_changed!(:#{attribute}) @#{attribute} = Intercom::Lib::FlatStore.new(value) @@ -29,8 +28,8 @@ def #{attribute} " end - def define_date_based_accessors(attribute, value, klass) - klass.class_eval %Q" + def define_date_based_accessors(attribute, value, object) + object.instance_eval %Q" def #{attribute}=(value) mark_field_as_changed!(:#{attribute}) @#{attribute} = value.nil? ? nil : value.to_i @@ -41,8 +40,8 @@ def #{attribute} " end - def define_standard_accessors(attribute, value, klass) - klass.class_eval %Q" + def define_standard_accessors(attribute, value, object) + object.instance_eval %Q" def #{attribute}=(value) mark_field_as_changed!(:#{attribute}) @#{attribute} = value diff --git a/spec/unit/intercom/contact_spec.rb b/spec/unit/intercom/contact_spec.rb index aca5f935..92d5525b 100644 --- a/spec/unit/intercom/contact_spec.rb +++ b/spec/unit/intercom/contact_spec.rb @@ -274,6 +274,7 @@ describe 'nested resources' do let(:contact) { Intercom::Contact.new(id: '1', client: client) } + let(:contact_no_tags) { Intercom::Contact.new(id: '2', client: client, tags: []) } let(:company) { Intercom::Company.new(id: '1') } let(:tag) { Intercom::Tag.new(id: '1') } let(:note) { Intercom::Note.new(body: "

Text for the note

") } @@ -299,6 +300,27 @@ _(proxy.resource_class).must_equal Intercom::Tag end + it 'returns correct tags from differring contacts' do + client.expects(:get).with('/contacts/1/tags', {}).returns({ + 'type' => 'tag.list', + 'tags' => [ + { + 'type' => 'tag', + 'id' => '1', + 'name' => 'VIP Customer' + }, + { + 'type' => 'tag', + 'id' => '2', + 'name' => 'Test tag' + } + ] + }) + + _(contact_no_tags.tags.map{ |t| t.id }).must_equal [] + _(contact.tags.map{ |t| t.id }).must_equal ['1', '2'] + end + it 'returns a collection proxy for listing companies' do proxy = contact.companies _(proxy.resource_name).must_equal 'companies' From 35af24bf6047b2e2143981071ce75311678e6299 Mon Sep 17 00:00:00 2001 From: Adam Martinik Date: Thu, 15 Apr 2021 13:19:01 +0200 Subject: [PATCH 25/47] Fix readme typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc9f24b8..6f2bc1ea 100644 --- a/README.md +++ b/README.md @@ -208,7 +208,7 @@ intercom.data_attributes.save(attribute) # Find all customer attributes including archived customer_attributes_incl_archived = intercom.data_attributes.find_all({"model": "contact", "include_archived": true}) -customer_attributes_incl_archived.each { |attr| p attribute.name } +customer_attributes_incl_archived.each { |attr| p attr.name } ``` #### Events From acd7d8916496f5721fe6a31f9ebfc1c00aef94bf Mon Sep 17 00:00:00 2001 From: Johnny Nader Date: Mon, 3 May 2021 18:59:08 +0100 Subject: [PATCH 26/47] update readme --- README.md | 88 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 6f2bc1ea..5359c114 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,26 @@ # intercom-ruby -Ruby bindings for the Intercom API (https://developers.intercom.io/reference). +[![Circle CI](https://circleci.com/gh/intercom/intercom-ruby.png?style=shield)](https://circleci.com/gh/intercom/intercom-ruby) +[![gem](https://img.shields.io/gem/v/intercom)](https://rubygems.org/gems/intercom) +![Intercom API Version](https://img.shields.io/badge/Intercom%20API%20Version-2.2-blue) + +> Ruby bindings for the [Intercom API](https://developers.intercom.io/reference). + +## Project Updates + +### Maintenance + +We're currently building a new team to provide in-depth and dedicated SDK support. + +In the meantime, we'll be operating on limited capacity, meaning all pull requests will be evaluated on a best effort basis and will be limited to critical issues. + +We'll communicate all relevant updates as we build this new team and support strategy in the coming months. [API Documentation](https://developers.intercom.io/docs) [Gem Documentation](http://rubydoc.info/github/intercom/intercom-ruby/master/frames) -For generating Intercom JavaScript script tags for Rails, please see https://github.com/intercom/intercom-rails. +For generating Intercom JavaScript script tags for Rails, please see [intercom/intercom-rails](https://github.com/intercom/intercom-rails) ## Upgrading information @@ -16,12 +30,15 @@ This version of the gem is compatible with `Ruby 2.1` and above. ## Installation - - gem install intercom +```bash +gem install intercom +``` Using bundler: - gem 'intercom', '~> 4.1' +```bundler +gem 'intercom', '~> 4.1' +``` ## Basic Usage @@ -46,29 +63,31 @@ You can also use the [omniauth-intercom lib](https://github.com/intercom/omniaut Resources this API supports: - https://api.intercom.io/contacts - https://api.intercom.io/visitors - https://api.intercom.io/companies - https://api.intercom.io/data_attributes - https://api.intercom.io/events - https://api.intercom.io/tags - https://api.intercom.io/notes - https://api.intercom.io/segments - https://api.intercom.io/conversations - https://api.intercom.io/messages - https://api.intercom.io/admins - https://api.intercom.io/teams - https://api.intercom.io/counts - https://api.intercom.io/subscriptions - https://api.intercom.io/jobs - https://api.intercom.io/articles - https://api.intercom.io/help_center/collections - https://api.intercom.io/help_center/sections - +```text +https://api.intercom.io/contacts +https://api.intercom.io/visitors +https://api.intercom.io/companies +https://api.intercom.io/data_attributes +https://api.intercom.io/events +https://api.intercom.io/tags +https://api.intercom.io/notes +https://api.intercom.io/segments +https://api.intercom.io/conversations +https://api.intercom.io/messages +https://api.intercom.io/admins +https://api.intercom.io/teams +https://api.intercom.io/counts +https://api.intercom.io/subscriptions +https://api.intercom.io/jobs +https://api.intercom.io/articles +https://api.intercom.io/help_center/collections +https://api.intercom.io/help_center/sections +``` ### Examples #### Contacts + Note that this is a new resource compatible only with the new [Contacts API](https://developers.intercom.com/intercom-api-reference/reference#contacts-model) released in API v2.0. ```ruby @@ -146,6 +165,7 @@ contact.companies.each {|c| p c.name} ``` #### Visitors + ```ruby # Get and update a visitor visitor = intercom.visitors.find(id: "5dd570e7b1b922452676af23") @@ -161,6 +181,7 @@ intercom.visitors.convert(visitor, user) ``` #### Companies + ```ruby # Find a company by company_id company = intercom.companies.find(company_id: "44") @@ -188,7 +209,9 @@ intercom.companies.scroll.each { |comp| puts comp.name} ``` #### Data Attributes + Data Attributes are a type of metadata used to describe your customer and company models. These include standard and custom attributes. + ```ruby # Create a new custom data attribute intercom.data_attributes.create({ name: "test_attribute", model: "contact", data_type: "string" }) @@ -212,6 +235,7 @@ customer_attributes_incl_archived.each { |attr| p attr.name } ``` #### Events + ```ruby intercom.events.create( event_name: "invited-friend", @@ -257,7 +281,8 @@ intercom.events.create( ) ``` -The metadata key values in the example are treated as follows- +The metadata key values in the example are treated as follows: + - order_date: a Date (key ends with '_date') - stripe_invoice: The identifier of the Stripe invoice (has a 'stripe_invoice' key) - order_number: a Rich Link (value contains 'url' and 'value' keys) @@ -266,6 +291,7 @@ The metadata key values in the example are treated as follows- *NB:* This version of the gem reserves the field name `type` in Event data. #### Tags + ```ruby # Iterate over all tags intercom.tags.all.each {|tag| "#{tag.id} - #{tag.name}" } @@ -279,12 +305,14 @@ tag = intercom.tags.untag(name: 'blue', companies: [{ company_id: "42ea2f1b93891 ``` #### Notes + ```ruby # Find a note by id note = intercom.notes.find(id: "123") ``` #### Segments + ```ruby # Find a segment segment = intercom.segments.find(id: segment_id) @@ -294,6 +322,7 @@ intercom.segments.all.each {|segment| puts "id: #{segment.id} name: #{segment.na ``` #### Conversations + ```ruby # Iterate over all conversations for your app intercom.conversations.all.each { |convo| ... } @@ -424,6 +453,7 @@ conversation.remove_contact(id: contact.id, admin_id: admin.id) ``` #### Full loading of an embedded entity + ```ruby # Given a conversation with a partial contact, load the full contact. This can be # done for any entity @@ -431,6 +461,7 @@ intercom.contacts.load(conversation.contacts.first) ``` #### Sending messages + ```ruby # InApp message from admin to user @@ -497,6 +528,7 @@ intercom.messages.create({ ``` #### Admins + ```ruby # Find access token owner (only with Personal Access Token and OAuth) intercom.admins.me @@ -507,6 +539,7 @@ intercom.admins.all.each {|admin| puts admin.email } ``` #### Teams + ```ruby # Find a team by id intercom.teams.find(id: team_id) @@ -544,6 +577,7 @@ intercom.subscriptions.all ``` #### Articles + ```ruby # Create an article article = intercom.articles.create(title: "New Article", author_id: "123456") @@ -577,6 +611,7 @@ intercom.articles.delete(article) ``` #### Collections + ```ruby # Create a collection collection = intercom.collections.create(name: "New Collection") @@ -609,6 +644,7 @@ intercom.collections.delete(collection) ``` #### Sections + ```ruby # Create a section section = intercom.sections.create(name: "New Section", parent_id: "123456") @@ -674,7 +710,7 @@ intercom.rate_limit_details You can handle the rate limits yourself but a simple option is to use the handle_rate_limit flag. This will automatically catch the 429 rate limit exceeded error and wait until the reset time to retry. After three retries a rate limit exception will be raised. Encountering this error frequently may require a revisiting of your usage of the API. -``` +```ruby intercom = Intercom::Client.new(token: ENV['AT'], handle_rate_limit: true) ``` From 095caa017e3da131cf3424e95a8c18af7dc2afb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Coelho?= Date: Tue, 1 Mar 2022 10:44:33 +0000 Subject: [PATCH 27/47] Fix collection successive iterations when there are multiple pages (#581) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Coelho Co-authored-by: Sean Healy --- lib/intercom/base_collection_proxy.rb | 1 + .../intercom/base_collection_proxy_spec.rb | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/intercom/base_collection_proxy.rb b/lib/intercom/base_collection_proxy.rb index 806e0125..bce14a9f 100644 --- a/lib/intercom/base_collection_proxy.rb +++ b/lib/intercom/base_collection_proxy.rb @@ -58,6 +58,7 @@ def has_next_link?(response_hash) @params[:starting_after] = paging_next['starting_after'] return true else + @params[:starting_after] = nil return false end end diff --git a/spec/unit/intercom/base_collection_proxy_spec.rb b/spec/unit/intercom/base_collection_proxy_spec.rb index ca37b720..473c4e39 100644 --- a/spec/unit/intercom/base_collection_proxy_spec.rb +++ b/spec/unit/intercom/base_collection_proxy_spec.rb @@ -4,7 +4,7 @@ let(:client) { Intercom::Client.new(token: 'token') } it "stops iterating if no starting after value" do - client.expects(:get).with("/contacts", {}). returns(page_of_contacts(false)) + client.expects(:get).with("/contacts", {}).returns(page_of_contacts(false)) emails = [] client.contacts.all.each { |contact| emails << contact.email } _(emails).must_equal %w[test1@example.com test2@example.com test3@example.com] @@ -15,6 +15,7 @@ client.expects(:get).with('/contacts', { starting_after: "EnCrYpTeDsTrInG" }).returns(page_of_contacts(false)) emails = [] client.contacts.all.each { |contact| emails << contact.email } + _(emails).must_equal %w[test1@example.com test2@example.com test3@example.com test1@example.com test2@example.com test3@example.com] end it "supports indexed array access" do @@ -27,4 +28,20 @@ emails = client.contacts.all.map { |contact| contact.email } _(emails).must_equal %w[test1@example.com test2@example.com test3@example.com] end + + it "keeps entire collection iterable after first iteration" do + contacts = client.contacts.all + emails_iter1 = [] + emails_iter2 = [] + expects_pagination = proc do + client.expects(:get).with("/contacts", {}).returns(page_of_contacts(true)) + client.expects(:get).with("/contacts", { starting_after: "EnCrYpTeDsTrInG" }).returns(page_of_contacts(false)) + end + + expects_pagination.call + contacts.each { |contact| emails_iter1 << contact.email } + expects_pagination.call + contacts.each { |contact| emails_iter2 << contact.email } + _(emails_iter1).must_equal emails_iter2 + end end From 39de43488146a51e38fd1cf7f1aa8aaf1b976c9a Mon Sep 17 00:00:00 2001 From: Farha Jawed Date: Tue, 1 Mar 2022 05:45:55 -0500 Subject: [PATCH 28/47] Add Intercom::GatewayTimeoutError to README (#574) Co-authored-by: Sean Healy Co-authored-by: Johnny Nader <30523158+johnnynader@users.noreply.github.com> --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fd21328a..467cd901 100644 --- a/README.md +++ b/README.md @@ -696,6 +696,7 @@ Intercom::RateLimitExceeded Intercom::AttributeNotSetError # Raised when you try to call a getter that does not exist on an object Intercom::MultipleMatchingUsersError Intercom::HttpError # Raised when response object is unexpectedly nil +Intercom::GatewayTimeoutError ``` ### Rate Limiting From b4b4be319a3578cc9fa7aa9d5bf1173f641ca394 Mon Sep 17 00:00:00 2001 From: Sean Healy Date: Tue, 1 Mar 2022 11:06:31 +0000 Subject: [PATCH 29/47] Bump intercom to 4.1.3 --- changes.txt | 5 +++++ lib/intercom/version.rb | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/changes.txt b/changes.txt index 08991b76..0783aa8d 100644 --- a/changes.txt +++ b/changes.txt @@ -1,3 +1,8 @@ +4.1.3 +- Updated ReadMe with more errors. +- Fixed issue where paginated requests could only be iterated through once. +- Moved Dynamic accessors from class level to instance level. + 4.1.2 - Adding support for company delete. - Adding support for archiving/unarchiving contacts. diff --git a/lib/intercom/version.rb b/lib/intercom/version.rb index df41bd76..211020ef 100644 --- a/lib/intercom/version.rb +++ b/lib/intercom/version.rb @@ -1,3 +1,3 @@ module Intercom #:nodoc: - VERSION = "4.1.2" + VERSION = "4.1.3" end From 675bea4ec617181e9dc207be9ccf620a45a0c839 Mon Sep 17 00:00:00 2001 From: Suma Prakash Date: Thu, 10 Nov 2022 09:53:47 +0000 Subject: [PATCH 30/47] Updating delete tag endpoint to match API 2.5 version changes --- README.md | 9 +++++++++ lib/intercom/errors.rb | 3 +++ lib/intercom/request.rb | 2 ++ spec/unit/intercom/tag_spec.rb | 6 ++++++ 4 files changed, 20 insertions(+) diff --git a/README.md b/README.md index 467cd901..b7a7188f 100644 --- a/README.md +++ b/README.md @@ -303,6 +303,15 @@ tag = intercom.tags.tag(name: 'blue', companies: [{company_id: "42ea2f1b93891f6a # Untag Companies tag = intercom.tags.untag(name: 'blue', companies: [{ company_id: "42ea2f1b93891f6a99000427" }]) ``` +```ruby +#delete tags +``` +Note: If there any depedent objects for the tag we are trying to delete, then an error TagHasDependentObjects will be thrown + +```ruby +tag = intercom.tags.find(id:"123") +intercom.tags.delete(tag) +``` #### Notes diff --git a/lib/intercom/errors.rb b/lib/intercom/errors.rb index 5d7e594a..b3af0bd5 100644 --- a/lib/intercom/errors.rb +++ b/lib/intercom/errors.rb @@ -99,6 +99,9 @@ class InvalidDocumentError < IntercomError; end # Raised when a merge is invalid class InvalidMergeError < IntercomError; end + # Raised when a tag has dependent objects + class TagHasDependentObjects < IntercomError; end + # # Non-public errors (internal to the gem) # diff --git a/lib/intercom/request.rb b/lib/intercom/request.rb index 0be75505..40379939 100644 --- a/lib/intercom/request.rb +++ b/lib/intercom/request.rb @@ -222,6 +222,8 @@ def execute(target_base_url = nil, token:, read_timeout: 90, open_timeout: 30, a raise Intercom::ApiVersionInvalid.new(error_details['message'], error_context) when 'scroll_exists' raise Intercom::ScrollAlreadyExistsError.new(error_details['message'], error_context) + when 'tag_has_dependent_objects' + raise Intercom::TagHasDependentObjects.new(error_details['message'], error_context) when nil, '' raise Intercom::UnexpectedError.new(message_for_unexpected_error_without_type(error_details, parsed_http_code), error_context) else diff --git a/spec/unit/intercom/tag_spec.rb b/spec/unit/intercom/tag_spec.rb index 07a7d4d9..b18c97a7 100644 --- a/spec/unit/intercom/tag_spec.rb +++ b/spec/unit/intercom/tag_spec.rb @@ -28,4 +28,10 @@ client.expects(:post).with('/tags', 'name' => 'Test Tag', 'companies' => [{ company_id: 'abc123', untag: true }, { company_id: 'def456', untag: true }], 'tag_or_untag' => 'untag').returns(test_tag) client.tags.untag(name: 'Test Tag', companies: [{ company_id: 'abc123' }, { company_id: 'def456' }]) end + + it 'delete tags' do + tag = Intercom::Tag.new('id' => '1') + client.expects(:delete).with('/tags/1', {}).returns(tag) + client.tags.delete(tag) + end end From a7bddce1f3514c3353cbaecb53781762abdf499e Mon Sep 17 00:00:00 2001 From: Suma Prakash Date: Thu, 10 Nov 2022 15:32:32 +0000 Subject: [PATCH 31/47] Changing the readme --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b7a7188f..e697169a 100644 --- a/README.md +++ b/README.md @@ -302,13 +302,11 @@ tag = intercom.tags.tag(name: 'blue', companies: [{company_id: "42ea2f1b93891f6a # Untag Companies tag = intercom.tags.untag(name: 'blue', companies: [{ company_id: "42ea2f1b93891f6a99000427" }]) -``` -```ruby + + #delete tags -``` -Note: If there any depedent objects for the tag we are trying to delete, then an error TagHasDependentObjects will be thrown -```ruby +#Note: If there any depedent objects for the tag we are trying to delete, then an error TagHasDependentObjects will be thrown tag = intercom.tags.find(id:"123") intercom.tags.delete(tag) ``` From d4242b71e49f9d69cddb4e02bc86e007e7744bcb Mon Sep 17 00:00:00 2001 From: Suma Prakash Date: Fri, 11 Nov 2022 14:16:13 +0000 Subject: [PATCH 32/47] Updating readme according to new version changes --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 467cd901..d3bc574f 100644 --- a/README.md +++ b/README.md @@ -525,6 +525,16 @@ intercom.messages.create({ }, body: "halp" }) + +#From version 2.6 the type contact is not supported and you would have to use leads to send messages to a lead. + +intercom.messages.create({ + from: { + type: "lead", + id: "536e5643as316c83104c400671" + }, + body: "halp" +}) ``` #### Admins From 43d6fbfb6e58d887bb991b1dab1a4f9fbee6426c Mon Sep 17 00:00:00 2001 From: Sean Healy Date: Fri, 11 Nov 2022 16:06:23 +0000 Subject: [PATCH 33/47] Add switch + data export api support --- README.md | 23 ++++++++++++++++ lib/intercom.rb | 4 +++ lib/intercom/client.rb | 8 ++++++ lib/intercom/export_content.rb | 7 +++++ lib/intercom/phone_call_redirect.rb | 7 +++++ lib/intercom/service/conversation.rb | 4 +++ lib/intercom/service/export_content.rb | 30 +++++++++++++++++++++ lib/intercom/service/phone_call_redirect.rb | 15 +++++++++++ spec/unit/intercom/export_content_spec.rb | 28 +++++++++++++++++++ spec/unit/intercom/phone_call_redirect.rb | 12 +++++++++ 10 files changed, 138 insertions(+) create mode 100644 lib/intercom/export_content.rb create mode 100644 lib/intercom/phone_call_redirect.rb create mode 100644 lib/intercom/service/export_content.rb create mode 100644 lib/intercom/service/phone_call_redirect.rb create mode 100644 spec/unit/intercom/export_content_spec.rb create mode 100644 spec/unit/intercom/phone_call_redirect.rb diff --git a/README.md b/README.md index 467cd901..4f84104e 100644 --- a/README.md +++ b/README.md @@ -676,6 +676,29 @@ intercom.collections.save(section) intercom.sections.delete(section) ``` +#### Phone Call Redirect (switch) + +```ruby +# Create a redirect +redirect = intercom.phone_call_redirect.create(phone_number: "+353871234567") + +``` + +#### Data Content Export + +```ruby +# Create a data export +export = intercom.data_content_export.create(created_at_after: 1667566801, created_at_before: 1668085202) + + +#View a data export +export = intercom.data_content_export.find(id: 'k0e27ohsyvh8ef3m') + +# Cancel a data export +export = intercom.data_content_export.cancel('k0e27ohsyvh8ef3m') + +``` + ### Errors There are different styles for error handling - some people prefer exceptions; some prefer nil and check; some prefer error objects/codes. Balancing these preferences alongside our wish to provide an idiomatic gem has brought us to use the current mechanism of throwing specific exceptions. Our approach in the client is to propagate errors and signal our failure loudly so that erroneous data does not get propagated through our customers' systems - in other words, if you see a `Intercom::ServiceUnavailableError` you know where the problem is. diff --git a/lib/intercom.rb b/lib/intercom.rb index b1793064..c398e681 100644 --- a/lib/intercom.rb +++ b/lib/intercom.rb @@ -21,6 +21,8 @@ require 'intercom/service/user' require 'intercom/service/lead' require 'intercom/deprecated_resources.rb' +require 'intercom/service/export_content' +require 'intercom/service/phone_call_redirect' require 'intercom/options' require 'intercom/client' require 'intercom/contact' @@ -46,6 +48,8 @@ require 'intercom/errors' require 'intercom/visitor' require 'intercom/data_attribute' +require 'intercom/export_content' +require 'intercom/phone_call_redirect' require 'json' ## diff --git a/lib/intercom/client.rb b/lib/intercom/client.rb index 883a99ae..d2514596 100644 --- a/lib/intercom/client.rb +++ b/lib/intercom/client.rb @@ -124,6 +124,14 @@ def collections Intercom::Service::Collection.new(self) end + def export_content + Intercom::Service::ExportContent.new(self) + end + + def phone_call_redirect + Intercom::Service::PhoneCallRedirect.new(self) + end + def get(path, params) execute_request Intercom::Request.get(path, params) end diff --git a/lib/intercom/export_content.rb b/lib/intercom/export_content.rb new file mode 100644 index 00000000..9ea7c3d5 --- /dev/null +++ b/lib/intercom/export_content.rb @@ -0,0 +1,7 @@ +require 'intercom/traits/api_resource' + +module Intercom + class ExportContent + include Traits::ApiResource + end +end diff --git a/lib/intercom/phone_call_redirect.rb b/lib/intercom/phone_call_redirect.rb new file mode 100644 index 00000000..61db81bb --- /dev/null +++ b/lib/intercom/phone_call_redirect.rb @@ -0,0 +1,7 @@ +require 'intercom/traits/api_resource' + +module Intercom + class PhoneCallRedirect + include Traits::ApiResource + end +end diff --git a/lib/intercom/service/conversation.rb b/lib/intercom/service/conversation.rb index 2a8d8ee4..77685db0 100644 --- a/lib/intercom/service/conversation.rb +++ b/lib/intercom/service/conversation.rb @@ -21,6 +21,10 @@ def collection_class Intercom::Conversation end + def collection_proxy_class + Intercom::BaseCollectionProxy + end + def mark_read(id) @client.put("/conversations/#{id}", read: true) end diff --git a/lib/intercom/service/export_content.rb b/lib/intercom/service/export_content.rb new file mode 100644 index 00000000..7c1e3897 --- /dev/null +++ b/lib/intercom/service/export_content.rb @@ -0,0 +1,30 @@ +require 'intercom/service/base_service' +require 'intercom/api_operations/find' +require 'intercom/api_operations/list' +require 'intercom/api_operations/save' + +module Intercom + module Service + class ExportContent < BaseService + include ApiOperations::Load + include ApiOperations::List + include ApiOperations::Find + include ApiOperations::Save + + def collection_class + Intercom::ExportContent + end + + def collection_name + 'export/content/data' + end + + def cancel(id) + response = @client.post("/export/cancel/#{id}", {}) + collection_class.new.from_response(response) + end + + end + end +end + diff --git a/lib/intercom/service/phone_call_redirect.rb b/lib/intercom/service/phone_call_redirect.rb new file mode 100644 index 00000000..425b57d2 --- /dev/null +++ b/lib/intercom/service/phone_call_redirect.rb @@ -0,0 +1,15 @@ +require 'intercom/service/base_service' +require 'intercom/api_operations/save' + +module Intercom + module Service + class PhoneCallRedirect < BaseService + include ApiOperations::Save + + def collection_class + Intercom::PhoneCallRedirect + end + + end + end +end diff --git a/spec/unit/intercom/export_content_spec.rb b/spec/unit/intercom/export_content_spec.rb new file mode 100644 index 00000000..6c7787b7 --- /dev/null +++ b/spec/unit/intercom/export_content_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe "Intercom::ExportContent" do + let(:client) { Intercom::Client.new(token: 'token') } + let(:job) { + { + job_identifier: "k0e27ohsyvh8ef3m", + status: "no_data", + download_url: "", + download_expires_at: 0 + } + } + + it "creates an export job" do + client.expects(:post).with("/export/content/data", {"created_at_after" => 1667566801, "created_at_before" => 1668085202}).returns(job) + client.export_content.create({"created_at_after" => 1667566801, "created_at_before" => 1668085202}) + end + + it "can view an export job" do + client.expects(:get).with("/export/content/data/#{job[:job_identifier]}", {}).returns(job) + client.export_content.find(id: job[:job_identifier]) + end + + it "Cancels a export job redirect" do + client.expects(:post).with("/export/cancel/#{job[:job_identifier]}", {}).returns(job) + client.export_content.cancel(job[:job_identifier]) + end +end diff --git a/spec/unit/intercom/phone_call_redirect.rb b/spec/unit/intercom/phone_call_redirect.rb new file mode 100644 index 00000000..02a38863 --- /dev/null +++ b/spec/unit/intercom/phone_call_redirect.rb @@ -0,0 +1,12 @@ +require 'spec_helper' + +describe "Intercom::PhoneCallRedirect" do + let(:client) { Intercom::Client.new(token: 'token') } + + it "creates a phone redirect" do + + client.expects(:post).with("/phone_call_redirect", {phone_number: "+353871234567"}) + client.phone_call_redirect.create(phone_number: "+353871234567") + end + +end From 0ee5c538d4cccad2349d99520c40838b8d30e6d3 Mon Sep 17 00:00:00 2001 From: Suma Prakash Date: Mon, 14 Nov 2022 11:38:43 +0000 Subject: [PATCH 34/47] Adding additional tests --- spec/unit/intercom/request_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spec/unit/intercom/request_spec.rb b/spec/unit/intercom/request_spec.rb index 2310bc79..6ec61cb8 100644 --- a/spec/unit/intercom/request_spec.rb +++ b/spec/unit/intercom/request_spec.rb @@ -124,6 +124,9 @@ def execute! let(:uri) {"https://api.intercom.io/conversations/reply"} let(:req) { Intercom::Request.put(uri, {}) } + let(:tag_uri) {"https://api.intercom.io/tags/"} + let(:del_req) { Intercom::Request.delete(tag_uri, {}) } + it 'should raise ResourceNotUniqueError error on resource_conflict code' do stub_request(:put, uri).to_return( status: [409, "Resource Already Exists"], @@ -153,5 +156,15 @@ def execute! expect { execute! }.must_raise(Intercom::ResourceNotFound) end + + it 'should raise TagHasDependentObjects error on tag_has_dependent_objects code' do + stub_request(:delete, tag_uri).to_return( + status: [400, "Bad Request"], + headers: { 'X-RateLimit-Reset' => (Time.now.utc + 10).to_i.to_s }, + body: { type: "error.list", errors: [ code: "tag_has_dependent_objects" ] }.to_json + ) + + expect { del_req.execute(tag_uri, token: 'test-token') }.must_raise(Intercom::TagHasDependentObjects) + end end end From a0970fd7862865cff2dcdd32a828b54440aa354e Mon Sep 17 00:00:00 2001 From: Suma Prakash Date: Mon, 14 Nov 2022 11:46:40 +0000 Subject: [PATCH 35/47] Updating readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a0d86a59..ef5b9fc1 100644 --- a/README.md +++ b/README.md @@ -306,7 +306,7 @@ tag = intercom.tags.untag(name: 'blue', companies: [{ company_id: "42ea2f1b93891 #delete tags -#Note: If there any depedent objects for the tag we are trying to delete, then an error TagHasDependentObjects will be thrown +# Note: If there any depedent objects for the tag we are trying to delete, then an error TagHasDependentObjects will be thrown. tag = intercom.tags.find(id:"123") intercom.tags.delete(tag) ``` From e5067f7ea80a58018a81d297948229c8170c9b1a Mon Sep 17 00:00:00 2001 From: Suma Prakash Date: Mon, 14 Nov 2022 11:49:25 +0000 Subject: [PATCH 36/47] Updating readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ef5b9fc1..f14c4364 100644 --- a/README.md +++ b/README.md @@ -304,9 +304,9 @@ tag = intercom.tags.tag(name: 'blue', companies: [{company_id: "42ea2f1b93891f6a tag = intercom.tags.untag(name: 'blue', companies: [{ company_id: "42ea2f1b93891f6a99000427" }]) -#delete tags +# Delete Tags -# Note: If there any depedent objects for the tag we are trying to delete, then an error TagHasDependentObjects will be thrown. +# Note : If there any depedent objects for the tag we are trying to delete, then an error TagHasDependentObjects will be thrown. tag = intercom.tags.find(id:"123") intercom.tags.delete(tag) ``` From 4fd8f0a38fb83d56d129f1b166723feb9d5e9374 Mon Sep 17 00:00:00 2001 From: Suma Prakash Date: Wed, 16 Nov 2022 17:00:59 +0000 Subject: [PATCH 37/47] Adding SDK endpoint to delete an archived contact --- README.md | 3 +++ lib/intercom/service/contact.rb | 4 ++++ spec/unit/intercom/contact_spec.rb | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/README.md b/README.md index 733b9051..6ffe3dd7 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,9 @@ intercom.contacts.unarchive(contact) # Delete a contact permanently intercom.contacts.delete(contact) +# Deletes an archived contact permanently +contact.delete_archived_contact("124") + # List all contacts contacts = intercom.contacts.all contacts.each { |contact| p contact.name } diff --git a/lib/intercom/service/contact.rb b/lib/intercom/service/contact.rb index 7b8b7504..3d01bf32 100644 --- a/lib/intercom/service/contact.rb +++ b/lib/intercom/service/contact.rb @@ -43,6 +43,10 @@ def unarchive(contact) contact end + def delete_archived_contact(id) + @client.delete("/#{collection_name}/#{id}", {}) + end + private def raise_invalid_merge_error raise Intercom::InvalidMergeError, 'Merging can only be performed on a lead into a user' end diff --git a/spec/unit/intercom/contact_spec.rb b/spec/unit/intercom/contact_spec.rb index 92d5525b..c8bd1a28 100644 --- a/spec/unit/intercom/contact_spec.rb +++ b/spec/unit/intercom/contact_spec.rb @@ -260,6 +260,12 @@ client.contacts.unarchive(contact) end + it 'deletes an archived contact' do + contact = Intercom::Contact.new('id' => '1','archived' =>true) + client.expects(:delete).with('/contacts/1', {}) + client.contacts.delete_archived_contact("1") + end + describe 'merging' do let(:lead) { Intercom::Contact.from_api(external_id: 'contact_id', role: 'lead') } let(:user) { Intercom::Contact.from_api(id: 'external_id', role: 'user') } From d5fe9b35df2f14e7edd979fe5a6bd4c8908c2cbf Mon Sep 17 00:00:00 2001 From: Sean Healy Date: Fri, 25 Nov 2022 11:45:23 +0000 Subject: [PATCH 38/47] Add opted out and in subscription types --- README.md | 23 +++++++++++++++++++ lib/intercom.rb | 2 ++ .../api_operations/nested_resource.rb | 2 -- lib/intercom/client.rb | 4 ++++ lib/intercom/contact.rb | 1 + lib/intercom/service/subscription_type.rb | 18 +++++++++++++++ lib/intercom/subscription_type.rb | 12 ++++++++++ lib/intercom/utils.rb | 6 ++++- spec/unit/intercom/contact_spec.rb | 11 +++++++++ 9 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 lib/intercom/service/subscription_type.rb create mode 100644 lib/intercom/subscription_type.rb diff --git a/README.md b/README.md index 733b9051..8226d686 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,16 @@ contact.remove_company(id: company.id) # List companies for a contact contact.companies.each {|c| p c.name} + +# attach a subscription_types on a contact +contact.create_subscription_types(id: '1') + +# List subscription_types for a contact +contact.subscription_types.each {|n| p n.body} + +# Remove subscription_types +contact.remove_subscription_type({ "id": subscription.id }) + ``` #### Visitors @@ -586,6 +596,19 @@ intercom.subscriptions.delete(subscription) intercom.subscriptions.all ``` + +#### Subscription Types + +Subscribe to events in Intercom to receive webhooks. + +```ruby + +# fetch a subscription +intercom.subscription_types.find(id: "1") + +intercom.subscription_types.all +``` + #### Articles ```ruby diff --git a/lib/intercom.rb b/lib/intercom.rb index c398e681..520b9036 100644 --- a/lib/intercom.rb +++ b/lib/intercom.rb @@ -12,6 +12,7 @@ require 'intercom/service/message' require 'intercom/service/note' require 'intercom/service/job' +require 'intercom/service/subscription_type' require 'intercom/service/subscription' require 'intercom/service/segment' require 'intercom/service/section' @@ -44,6 +45,7 @@ require 'intercom/article' require 'intercom/request' require 'intercom/subscription' +require 'intercom/subscription_type' require 'intercom/team' require 'intercom/errors' require 'intercom/visitor' diff --git a/lib/intercom/api_operations/nested_resource.rb b/lib/intercom/api_operations/nested_resource.rb index 3dedef7f..961d7362 100644 --- a/lib/intercom/api_operations/nested_resource.rb +++ b/lib/intercom/api_operations/nested_resource.rb @@ -13,9 +13,7 @@ def nested_resource_methods(resource, raise ArgumentError, 'operations array required' if operations.nil? resource_url_method = :"#{resource_plural}_url" - resource_name = Utils.resource_class_to_collection_name(self) - define_method(resource_url_method.to_sym) do |id, nested_id = nil| url = "/#{resource_name}/#{id}/#{path}" url += "/#{nested_id}" unless nested_id.nil? diff --git a/lib/intercom/client.rb b/lib/intercom/client.rb index d2514596..5b3f607f 100644 --- a/lib/intercom/client.rb +++ b/lib/intercom/client.rb @@ -84,6 +84,10 @@ def subscriptions Intercom::Service::Subscription.new(self) end + def subscription_types + Intercom::Service::SubscriptionType.new(self) + end + def segments Intercom::Service::Segment.new(self) end diff --git a/lib/intercom/contact.rb b/lib/intercom/contact.rb index f5332ab5..d9056082 100644 --- a/lib/intercom/contact.rb +++ b/lib/intercom/contact.rb @@ -12,6 +12,7 @@ class Contact nested_resource_methods :tag, operations: %i[add delete list] nested_resource_methods :note, operations: %i[create list] + nested_resource_methods :subscription_type, operations: %i[create delete list] nested_resource_methods :company, operations: %i[add delete list] nested_resource_methods :segment, operations: %i[list] diff --git a/lib/intercom/service/subscription_type.rb b/lib/intercom/service/subscription_type.rb new file mode 100644 index 00000000..c1de4879 --- /dev/null +++ b/lib/intercom/service/subscription_type.rb @@ -0,0 +1,18 @@ +require 'intercom/api_operations/list' +require 'intercom/api_operations/find_all' +require 'intercom/api_operations/find' + +module Intercom + module Service + class SubscriptionType < BaseService + include ApiOperations::List + include ApiOperations::Find + include ApiOperations::FindAll + include ApiOperations::Delete + + def collection_class + Intercom::SubscriptionType + end + end + end +end diff --git a/lib/intercom/subscription_type.rb b/lib/intercom/subscription_type.rb new file mode 100644 index 00000000..d53c2762 --- /dev/null +++ b/lib/intercom/subscription_type.rb @@ -0,0 +1,12 @@ + +require 'intercom/traits/api_resource' + +module Intercom + class SubscriptionType + include Traits::ApiResource + + def self.collection_proxy_class + Intercom::BaseCollectionProxy + end + end +end diff --git a/lib/intercom/utils.rb b/lib/intercom/utils.rb index ce0bcd74..2d39c0d1 100644 --- a/lib/intercom/utils.rb +++ b/lib/intercom/utils.rb @@ -25,6 +25,10 @@ def constantize(camel_cased_word) constant end + def camelize(snake_cased_word) + snake_cased_word.split(/_/).map(&:capitalize).join + end + def resource_class_to_singular_name(resource_class) resource_name = resource_class.to_s.split('::')[-1] resource_name = maybe_underscore_name(resource_name) @@ -40,7 +44,7 @@ def resource_class_to_collection_name(resource_class) end def constantize_resource_name(resource_name) - class_name = Utils.singularize(resource_name.capitalize) + class_name = camelize Utils.singularize(resource_name.capitalize) define_lightweight_class(class_name) unless Intercom.const_defined?(class_name, false) namespaced_class_name = "Intercom::#{class_name}" constantize namespaced_class_name diff --git a/spec/unit/intercom/contact_spec.rb b/spec/unit/intercom/contact_spec.rb index 92d5525b..f79f6b34 100644 --- a/spec/unit/intercom/contact_spec.rb +++ b/spec/unit/intercom/contact_spec.rb @@ -276,6 +276,7 @@ let(:contact) { Intercom::Contact.new(id: '1', client: client) } let(:contact_no_tags) { Intercom::Contact.new(id: '2', client: client, tags: []) } let(:company) { Intercom::Company.new(id: '1') } + let(:subscription) { Intercom::Subscription.new(id: '1', client: client) } let(:tag) { Intercom::Tag.new(id: '1') } let(:note) { Intercom::Note.new(body: "

Text for the note

") } @@ -338,6 +339,11 @@ contact.add_tag({ "id": tag.id }) end + it 'removes a subscription to a contact' do + client.expects(:delete).with("/contacts/1/subscription_types/#{subscription.id}", "id": subscription.id).returns(subscription.to_hash) + contact.remove_subscription_type({ "id": subscription.id }) + end + it 'removes a tag from a contact' do client.expects(:delete).with("/contacts/1/tags/#{tag.id}", "id": tag.id ).returns(tag.to_hash) contact.remove_tag({ "id": tag.id }) @@ -387,6 +393,11 @@ contact.create_note({body: note.body}) end + it 'adds a subscription to a contact' do + client.expects(:post).with('/contacts/1/subscription_types', "id": subscription.id).returns(subscription.to_hash) + contact.create_subscription_type({ "id": subscription.id }) + end + it 'adds a tag to a contact' do client.expects(:post).with('/contacts/1/tags', "id": tag.id).returns(tag.to_hash) contact.add_tag({ "id": tag.id }) From 428f6c4fbfef081328474066e72556846b37000d Mon Sep 17 00:00:00 2001 From: Suma Prakash Date: Fri, 2 Dec 2022 13:03:26 +0000 Subject: [PATCH 39/47] Updating the readme and url for subscriptions --- README.md | 19 +++++++++++-------- lib/intercom/contact.rb | 2 +- spec/unit/intercom/contact_spec.rb | 4 ++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 08e81fa3..45f8511c 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,9 @@ https://api.intercom.io/jobs https://api.intercom.io/articles https://api.intercom.io/help_center/collections https://api.intercom.io/help_center/sections +https://api.intercom.io/phone_call_redirects +https://api.intercom.io/subscription_types +https://api.intercom.io/export/content/data ``` ### Examples @@ -115,7 +118,7 @@ intercom.contacts.unarchive(contact) intercom.contacts.delete(contact) # Deletes an archived contact permanently -contact.delete_archived_contact("124") +intercom.contacts.delete_archived_contact(contact.id) # List all contacts contacts = intercom.contacts.all @@ -167,13 +170,13 @@ contact.remove_company(id: company.id) contact.companies.each {|c| p c.name} # attach a subscription_types on a contact -contact.create_subscription_types(id: '1') +contact.create_subscription_types(id: subscription_type.id) # List subscription_types for a contact -contact.subscription_types.each {|n| p n.body} +contact.subscription_types.each {|n| p n.id} # Remove subscription_types -contact.remove_subscription_type({ "id": subscription.id }) +contact.remove_subscription_type({ "id": subscription_type.id }) ``` @@ -609,7 +612,7 @@ intercom.subscriptions.all #### Subscription Types -Subscribe to events in Intercom to receive webhooks. +List all the subscription types that a contact can opt in to ```ruby @@ -731,14 +734,14 @@ redirect = intercom.phone_call_redirect.create(phone_number: "+353871234567") ```ruby # Create a data export -export = intercom.data_content_export.create(created_at_after: 1667566801, created_at_before: 1668085202) +export = intercom.export_content.create(created_at_after: 1667566801, created_at_before: 1668085202) #View a data export -export = intercom.data_content_export.find(id: 'k0e27ohsyvh8ef3m') +export = intercom.export_content.find(id: 'k0e27ohsyvh8ef3m') # Cancel a data export -export = intercom.data_content_export.cancel('k0e27ohsyvh8ef3m') +export = intercom.export_content.cancel('k0e27ohsyvh8ef3m') ``` diff --git a/lib/intercom/contact.rb b/lib/intercom/contact.rb index d9056082..6f656d9e 100644 --- a/lib/intercom/contact.rb +++ b/lib/intercom/contact.rb @@ -12,7 +12,7 @@ class Contact nested_resource_methods :tag, operations: %i[add delete list] nested_resource_methods :note, operations: %i[create list] - nested_resource_methods :subscription_type, operations: %i[create delete list] + nested_resource_methods :subscription_type, path: 'subscriptions', operations: %i[create delete list] nested_resource_methods :company, operations: %i[add delete list] nested_resource_methods :segment, operations: %i[list] diff --git a/spec/unit/intercom/contact_spec.rb b/spec/unit/intercom/contact_spec.rb index 0553dc37..a8ffd978 100644 --- a/spec/unit/intercom/contact_spec.rb +++ b/spec/unit/intercom/contact_spec.rb @@ -346,7 +346,7 @@ end it 'removes a subscription to a contact' do - client.expects(:delete).with("/contacts/1/subscription_types/#{subscription.id}", "id": subscription.id).returns(subscription.to_hash) + client.expects(:delete).with("/contacts/1/subscriptions/#{subscription.id}", "id": subscription.id).returns(subscription.to_hash) contact.remove_subscription_type({ "id": subscription.id }) end @@ -400,7 +400,7 @@ end it 'adds a subscription to a contact' do - client.expects(:post).with('/contacts/1/subscription_types', "id": subscription.id).returns(subscription.to_hash) + client.expects(:post).with('/contacts/1/subscriptions', "id": subscription.id).returns(subscription.to_hash) contact.create_subscription_type({ "id": subscription.id }) end From bf0ea223ec1874065ae752f5f9c3806be1949c26 Mon Sep 17 00:00:00 2001 From: Suma Prakash Date: Mon, 5 Dec 2022 12:23:39 +0000 Subject: [PATCH 40/47] Updating the documentation --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 45f8511c..dcb047e7 100644 --- a/README.md +++ b/README.md @@ -350,6 +350,8 @@ intercom.segments.all.each {|segment| puts "id: #{segment.id} name: #{segment.na # Iterate over all conversations for your app intercom.conversations.all.each { |convo| ... } +# The below method of finding conversations by using the find_all method work only for API versions 2.5 and below + # FINDING CONVERSATIONS FOR AN ADMIN # Iterate over all conversations (open and closed) assigned to an admin intercom.conversations.find_all(type: 'admin', id: '7').each {|convo| ... } From aec1e944566a786f92abb250874dc1616e71cb76 Mon Sep 17 00:00:00 2001 From: Suma Prakash Date: Tue, 6 Dec 2022 14:27:43 +0000 Subject: [PATCH 41/47] Adding a fix --- lib/intercom/base_collection_proxy.rb | 6 +++++- lib/intercom/lib/typed_json_deserializer.rb | 11 ++++++++--- lib/intercom/utils.rb | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/intercom/base_collection_proxy.rb b/lib/intercom/base_collection_proxy.rb index bce14a9f..ee622d79 100644 --- a/lib/intercom/base_collection_proxy.rb +++ b/lib/intercom/base_collection_proxy.rb @@ -45,7 +45,11 @@ def deserialize_response_hash(response_hash, block) Utils.entity_key_from_type(top_level_type) end response_hash[top_level_entity_key].each do |object_json| - block.call Lib::TypedJsonDeserializer.new(object_json, @client).deserialize + if top_level_type == 'event.summary' + block.call Lib::TypedJsonDeserializer.new(object_json, @client, top_level_type).deserialize + else + block.call Lib::TypedJsonDeserializer.new(object_json, @client).deserialize + end end end diff --git a/lib/intercom/lib/typed_json_deserializer.rb b/lib/intercom/lib/typed_json_deserializer.rb index 17ed5ea3..155d2325 100644 --- a/lib/intercom/lib/typed_json_deserializer.rb +++ b/lib/intercom/lib/typed_json_deserializer.rb @@ -9,9 +9,10 @@ module Lib class TypedJsonDeserializer attr_reader :json - def initialize(json, client) + def initialize(json, client, type = nil) @json = json @client = client + @type = type end def deserialize @@ -27,7 +28,7 @@ def deserialize private def blank_object_type?(object_type) - object_type.nil? || object_type == '' + object_type.nil? || object_type == '' && @type.nil? end def list_object_type?(object_type) @@ -48,7 +49,11 @@ def deserialize_object(object_json) end def object_type - @object_type ||= json['type'] + if !@type.nil? + @object_type = @type + else + @object_type ||= json['type'] + end end def object_entity_key diff --git a/lib/intercom/utils.rb b/lib/intercom/utils.rb index 2d39c0d1..6ccba8cc 100644 --- a/lib/intercom/utils.rb +++ b/lib/intercom/utils.rb @@ -69,6 +69,7 @@ def entity_key_from_type(type) is_list = type.split('.')[1] == 'list' entity_name = type.split('.')[0] + return Utils.pluralize(entity_name) if entity_name == 'event' is_list ? Utils.pluralize(entity_name) : entity_name end end From c9d289fc70cddd389b3a007290d9e559b1970dcf Mon Sep 17 00:00:00 2001 From: Suma Prakash Date: Tue, 6 Dec 2022 15:46:53 +0000 Subject: [PATCH 42/47] Adding unit test cass --- README.md | 8 ++++++++ spec/unit/intercom/event_spec.rb | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/README.md b/README.md index dcb047e7..94a6e3c2 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,14 @@ intercom.events.create( # Retrieve event list for user with id:'123abc' intercom.events.find_all("type" => "user", "intercom_user_id" => "123abc") + +# Retrieve the event summary for user with id: 'abc' this will return an event object with the following characteristics: +# name - name of the event +# first - time when event first occured. +# last - time when event last occured +# count - nmber of times the event occured +# description - description of the event + events = intercom.events.find_all(type: 'user',intercom_user_id: 'abc',summary: true) ``` Metadata Objects support a few simple types that Intercom can present on your behalf diff --git a/spec/unit/intercom/event_spec.rb b/spec/unit/intercom/event_spec.rb index 125d9996..5d62551f 100644 --- a/spec/unit/intercom/event_spec.rb +++ b/spec/unit/intercom/event_spec.rb @@ -22,6 +22,13 @@ _(event_names).must_equal %W(invited-friend) end + it "able to fetch event summary" do + client.expects(:get).with("/events", type: 'user', email: 'joe@example.com', summary: true).returns(page_of_events(false)) + event_names = [] + client.events.find_all(type: 'user', email: 'joe@example.com',summary: true).each { |event| event_names << event.event_name } + _(event_names).must_equal %W(invited-friend) + end + it "keeps iterating if next link" do client.expects(:get).with("/events", type: 'user', email: 'joe@example.com').returns(page_of_events(true)) client.expects(:get).with("https://api.intercom.io/events?type=user&intercom_user_id=55a3b&before=144474756550", {}).returns(page_of_events(false)) From a6a2460827e88984fd1f7597ddb92856cc86aeb0 Mon Sep 17 00:00:00 2001 From: suma-prakash <107560946+suma-prakash@users.noreply.github.com> Date: Tue, 6 Dec 2022 16:00:01 +0000 Subject: [PATCH 43/47] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 94a6e3c2..1f29b37e 100644 --- a/README.md +++ b/README.md @@ -278,7 +278,7 @@ intercom.events.create( # name - name of the event # first - time when event first occured. # last - time when event last occured -# count - nmber of times the event occured +# count - number of times the event occured # description - description of the event events = intercom.events.find_all(type: 'user',intercom_user_id: 'abc',summary: true) ``` From 60acc50c59a22c93cbb788077caa8572beeda759 Mon Sep 17 00:00:00 2001 From: Sean Healy Date: Wed, 7 Dec 2022 15:17:06 +0000 Subject: [PATCH 44/47] Bump intercom to 4.2.0 --- README.md | 4 ++-- lib/intercom/version.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1f29b37e..b60d9ac2 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Circle CI](https://circleci.com/gh/intercom/intercom-ruby.png?style=shield)](https://circleci.com/gh/intercom/intercom-ruby) [![gem](https://img.shields.io/gem/v/intercom)](https://rubygems.org/gems/intercom) -![Intercom API Version](https://img.shields.io/badge/Intercom%20API%20Version-2.2-blue) +![Intercom API Version](https://img.shields.io/badge/Intercom%20API%20Version-2.6-blue) > Ruby bindings for the [Intercom API](https://developers.intercom.io/reference). @@ -274,7 +274,7 @@ intercom.events.create( # Retrieve event list for user with id:'123abc' intercom.events.find_all("type" => "user", "intercom_user_id" => "123abc") -# Retrieve the event summary for user with id: 'abc' this will return an event object with the following characteristics: +# Retrieve the event summary for user with id: 'abc' this will return an event object with the following characteristics: # name - name of the event # first - time when event first occured. # last - time when event last occured diff --git a/lib/intercom/version.rb b/lib/intercom/version.rb index 211020ef..0529f64a 100644 --- a/lib/intercom/version.rb +++ b/lib/intercom/version.rb @@ -1,3 +1,3 @@ module Intercom #:nodoc: - VERSION = "4.1.3" + VERSION = "4.2.0" end From 4a90839f76aa07d5bda6891e7fc3b1019e7cc63c Mon Sep 17 00:00:00 2001 From: Tom Dooner Date: Thu, 15 Dec 2022 11:01:03 -0800 Subject: [PATCH 45/47] Fix query params not being used in Intercom::BaseCollectionProxy Arbitrary @query params could be passed in to filter resources, e.g. via the `#find_all` method. These params were not being forwarded through to the underlying HTTP client by BaseCollectionProxy in the same way that they are in ClientCollectionProxy. --- lib/intercom/base_collection_proxy.rb | 5 +---- spec/unit/intercom/base_collection_proxy_spec.rb | 5 +++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/intercom/base_collection_proxy.rb b/lib/intercom/base_collection_proxy.rb index ee622d79..8fb59451 100644 --- a/lib/intercom/base_collection_proxy.rb +++ b/lib/intercom/base_collection_proxy.rb @@ -68,10 +68,7 @@ def has_next_link?(response_hash) end def payload - payload = {} - payload[:per_page] = @params[:per_page] if @params[:per_page] - payload[:starting_after] = @params[:starting_after] if @params[:starting_after] - payload + @params.keep_if { |k, v| !v.nil? }.to_h end end end diff --git a/spec/unit/intercom/base_collection_proxy_spec.rb b/spec/unit/intercom/base_collection_proxy_spec.rb index 473c4e39..02efed90 100644 --- a/spec/unit/intercom/base_collection_proxy_spec.rb +++ b/spec/unit/intercom/base_collection_proxy_spec.rb @@ -44,4 +44,9 @@ contacts.each { |contact| emails_iter2 << contact.email } _(emails_iter1).must_equal emails_iter2 end + + it "supports query params" do + client.expects(:get).with("/conversations", {:intercom_user_id => 'abcdef0000'}).returns(test_conversation_list) + _(client.conversations.find_all(:intercom_user_id => 'abcdef0000').map(&:id)).must_equal %w[147] + end end From e640a2dfde500335acf2b4c0962e4c241fa39308 Mon Sep 17 00:00:00 2001 From: Sean Healy Date: Fri, 16 Dec 2022 10:55:00 +0000 Subject: [PATCH 46/47] Add spec for find all on conversations --- spec/unit/intercom/company_spec.rb | 2 +- spec/unit/intercom/conversation_spec.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/spec/unit/intercom/company_spec.rb b/spec/unit/intercom/company_spec.rb index 03fe762b..ac0f0e11 100644 --- a/spec/unit/intercom/company_spec.rb +++ b/spec/unit/intercom/company_spec.rb @@ -9,7 +9,7 @@ _(proc { client.companies.find(:company_id => "4")}).must_raise Intercom::HttpError end - it "on find_all" do + it "on all" do client.expects(:get).with("/companies", {}).returns(nil) _(proc { client.companies.all.each {|company| }}).must_raise Intercom::HttpError end diff --git a/spec/unit/intercom/conversation_spec.rb b/spec/unit/intercom/conversation_spec.rb index 79919d54..d585eea6 100644 --- a/spec/unit/intercom/conversation_spec.rb +++ b/spec/unit/intercom/conversation_spec.rb @@ -13,6 +13,11 @@ client.conversations.all.each { |c| } end + it "can filter conversations based on params" do + client.expects(:get).with("/conversations", {type: 'user', intercom_user_id: '123456789'}).returns(test_conversation_list) + client.conversations.find_all(type: 'user', intercom_user_id: '123456789').each { |c| } + end + it 'marks a conversation as read' do client.expects(:put).with('/conversations/147', { read: true }) client.conversations.mark_read('147') From d082c4040fbaf16e2edd29f35c63adcd545c8ab5 Mon Sep 17 00:00:00 2001 From: Jack Oddy Date: Fri, 17 Feb 2023 10:07:38 +0000 Subject: [PATCH 47/47] Fixes typo in README `create_subscription_types` does not exist on the contact class --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b60d9ac2..8ad928a4 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ contact.remove_company(id: company.id) contact.companies.each {|c| p c.name} # attach a subscription_types on a contact -contact.create_subscription_types(id: subscription_type.id) +contact.create_subscription_type(id: subscription_type.id) # List subscription_types for a contact contact.subscription_types.each {|n| p n.id}