Code Monkey home page Code Monkey logo

intercom-ruby's Introduction

intercom-ruby

Circle CI gem Intercom API Version

Ruby bindings for the Intercom API.

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

Gem Documentation

For generating Intercom JavaScript script tags for Rails, please see intercom/intercom-rails

Upgrading information

Version 4 of intercom-ruby is not backwards compatible with previous versions. Please see our migration guide for full details of breaking changes.

This version of the gem is compatible with Ruby 2.1 and above.

Installation

gem install intercom

Using bundler:

gem 'intercom', '~> 4.1'

Basic Usage

Configure your client

If you already have a personal access token you can find it here. If you want to create or learn more about personal access tokens then you can find more info here.

# With an OAuth or Personal Access token:
intercom = Intercom::Client.new(token: 'my_token')
# With a versioned app:
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 for Intercom. You can also use the omniauth-intercom lib which is a middleware helping you to handle the authentication process with Intercom.

Resources

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
https://api.intercom.io/phone_call_redirects
https://api.intercom.io/subscription_types
https://api.intercom.io/export/content/data

Examples

Contacts

Note that this is a new resource compatible only with the new Contacts API released in API v2.0.

# Create a contact with "lead" role
contact = intercom.contacts.create(email: "[email protected]", role: "lead")

# Get a single contact using their intercom_id
intercom.contacts.find(id: contact.id)

# Update a contact
contact.name = "New name"
intercom.contacts.save(contact)

# Update a contact's role from "lead" to "user"
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)

# Deletes an archived contact permanently
intercom.contacts.delete_archived_contact(contact.id)

# List all contacts
contacts = intercom.contacts.all
contacts.each { |contact| p contact.name }

# Search for contacts by email
contacts = intercom.contacts.search(
  "query": {
    "field": 'email',
    "operator": '=',
    "value": '[email protected]'
  }
)
contacts.each {|c| p c.email}
# 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
lead = intercom.contacts.create(email: "[email protected]", role: "lead")
intercom.contacts.merge(lead, intercom.contacts.find(id: "5db2e80ab1b92243d2188cfe"))

# Add a tag to a contact
tag = intercom.tags.find(id: "123")
contact.add_tag(id: tag.id)

# Remove a tag
contact.remove_tag(id: tag.id)

# List tags for a contact
contact.tags.each {|t| p t.name}

# Create a note on a contact
contact.create_note(body: "<p>Text for the note</p>")

# 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)

# Remove a contact from a company
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_type(id: subscription_type.id)

# List subscription_types for a contact
contact.subscription_types.each {|n| p n.id}

# Remove subscription_types
contact.remove_subscription_type({ "id": subscription_type.id })

Visitors

# Get and update a visitor
visitor = intercom.visitors.find(id: "5dd570e7b1b922452676af23")
visitor.name = "New name"
intercom.visitors.save(visitor)

# Convert a visitor into a lead
intercom.visitors.convert(visitor)

# Convert a visitor into a user
user = intercom.contacts.find(id: "5db2e7f5b1b92243d2188cb3")
intercom.visitors.convert(visitor, user)

Companies

# Find a company by company_id
company = intercom.companies.find(company_id: "44")

# Find a company by name
company = intercom.companies.find(name: "Some company")

# Find a company by id
company = intercom.companies.find(id: "41e66f0313708347cb0000d0")

# Update a company
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 }

# Get a large list of companies using scroll
intercom.companies.scroll.each { |comp| puts comp.name}
# Please see users scroll for more details of how to use scroll

Data Attributes

Data Attributes are a type of metadata used to describe your customer and company models. These include standard and custom attributes.

# Create a new custom data attribute
intercom.data_attributes.create({ name: "test_attribute", model: "contact", data_type: "string" })

# List all data attributes
attributes = intercom.data_attributes.all
attributes.each { |attribute| p attribute.name }

# Update an attribute
attribute = intercom.data_attributes.all.first
attribute.label = "New label"
intercom.data_attributes.save(attribute)

# Archive an attribute
attribute.archived = true
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 attr.name }

Events

intercom.events.create(
  event_name: "invited-friend",
  created_at: Time.now.to_i,
  email: user.email,
  metadata: {
    "invitee_email" => "[email protected]",
    invite_code: "ADDAFRIEND",
    "found_date" => 12909364407
  }
)

# Alternatively, use "user_id" in case your app allows multiple accounts having the same email
intercom.events.create(
  event_name: "invited-friend",
  created_at: Time.now.to_i,
  user_id: user.uuid,
)

# 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 - number 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

intercom.events.create(
  event_name: "placed-order",
  email: current_user.email,
  created_at: 1403001013,
  metadata: {
    order_date: Time.now.to_i,
    stripe_invoice: 'inv_3434343434',
    order_number: {
      value: '3434-3434',
      url: 'https://example.org/orders/3434-3434'
    },
    price: {
      currency: 'usd',
      amount: 2999
    }
  }
)

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)
  • price: An Amount in US Dollars (value contains 'amount' and 'currency' keys)

NB: This version of the gem reserves the field name type in Event data.

Tags

# Iterate over all tags
intercom.tags.all.each {|tag| "#{tag.id} - #{tag.name}" }
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" }])


# Delete Tags

# 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)

Notes

# Find a note by id
note = intercom.notes.find(id: "123")

Segments

# Find a segment
segment = intercom.segments.find(id: segment_id)

# Iterate over all segments
intercom.segments.all.each {|segment| puts "id: #{segment.id} name: #{segment.name}"}

Conversations

# 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| ... }
# Iterate over all open conversations assigned to an admin
intercom.conversations.find_all(type: 'admin', id: 7, open: true).each {|convo| ... }
# Iterate over closed conversations assigned to an admin
intercom.conversations.find_all(type: 'admin', id: 7, open: false).each {|convo| ... }
# Iterate over closed conversations which are assigned to an admin, and where updated_at is before a certain moment in time
intercom.conversations.find_all(type: 'admin', id: 7, open: false, before: 1374844930).each {|convo| ... }

# FINDING CONVERSATIONS FOR A USER
# Iterate over all conversations (read + unread, correct) with a user based on the users email
intercom.conversations.find_all(email: '[email protected]', type: 'user').each {|convo| ... }
# Iterate over through all conversations (read + unread) with a user based on the users email
intercom.conversations.find_all(email: '[email protected]', type: 'user', unread: false).each {|convo| ... }
# Iterate over all unread conversations with a user based on the users email
intercom.conversations.find_all(email: '[email protected]', type: 'user', unread: true).each {|convo| ... }
# Iterate over all conversations for a user with their Intercom user ID
intercom.conversations.find_all(intercom_user_id: '536e564f316c83104c000020', type: 'user').each {|convo| ... }
# Iterate over all conversations for a lead
# NOTE: to iterate over a lead's conversations you MUST use their Intercom User ID and type User
intercom.conversations.find_all(intercom_user_id: lead.id, type: 'user').each {|convo| ... }

# FINDING A SINGLE CONVERSATION
conversation = intercom.conversations.find(id: '1')

# INTERACTING WITH THE PARTS OF A CONVERSATION
# Getting the subject of a part (only applies to email-based conversations)
conversation.source.subject

# Get the part_type of the first part
conversation.conversation_parts.first.part_type

# Get the body of the second part
conversation.conversation_parts[1].body

# Get statistics related to the conversation
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

# REPLYING TO CONVERSATIONS
# User (identified by email) replies with a comment
intercom.conversations.reply(id: conversation.id, type: 'user', email: '[email protected]', message_type: 'comment', body: 'foo')
# Admin (identified by id) replies with a comment
intercom.conversations.reply(id: conversation.id, type: 'admin', admin_id: '123', message_type: 'comment', body: 'bar')
# User (identified by email) replies with a comment and attachment
intercom.conversations.reply(id: conversation.id, type: 'user', email: '[email protected]', message_type: 'comment', body: 'foo', attachment_urls: ['http://www.example.com/attachment.jpg'])

#reply to a user's last conversation
intercom.conversations.reply_to_last(type: 'user', body: 'Thanks again', message_type: 'comment', user_id: '12345', admin_id: '123')

# Open
intercom.conversations.open(id: conversation.id, admin_id: '123')

# Close
intercom.conversations.close(id: conversation.id, admin_id: '123')

# Assign
# Note: Conversations can be assigned to teams. However, the entity that performs the operation of assigning the conversation has to be an existing teammate.
#       You can use `intercom.admins.all.each {|a| puts a.inspect if a.type == 'admin' }` to list all of your teammates.
intercom.conversations.assign(id: conversation.id, admin_id: '123', assignee_id: '124')

# Snooze
intercom.conversations.snooze(id: conversation.id, admin_id: '123', snoozed_until: 9999999999)

# Reply and Open
intercom.conversations.reply(id: conversation.id, type: 'admin', admin_id: '123', message_type: 'open', body: 'bar')

# Reply and Close
intercom.conversations.reply(id: conversation.id, type: 'admin', admin_id: '123', message_type: 'close', body: 'bar')

# Admin reply to last conversation
intercom.conversations.reply_to_last(intercom_user_id: '5678', type: 'admin', admin_id: '123', message_type: 'comment', body: 'bar')

# User reply to last conversation
intercom.conversations.reply_to_last(intercom_user_id: '5678', type: 'user', message_type: 'comment', body: 'bar')

# ASSIGNING CONVERSATIONS TO ADMINS
intercom.conversations.reply(id: conversation.id, type: 'admin', assignee_id: assignee_admin.id, admin_id: admin.id, message_type: 'assignment')

# MARKING A CONVERSATION AS READ
intercom.conversations.mark_read(conversation.id)

# RUN ASSIGNMENT RULES
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

# Search for open conversations sorted by the created_at date
conversations = intercom.conversations.search(
  query: {
    field: "open",
    operator: "=",
    value: true
  },
  sort_field: "created_at",
  sort_order: "descending"
)
conversations.each {|c| p c.id}

# Tagging for conversations
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")

# 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_contact(id: contact.id, admin_id: admin.id)

Full loading of an embedded entity

# Given a conversation with a partial contact, load the full contact. This can be
# done for any entity
intercom.contacts.load(conversation.contacts.first)

Sending messages

# InApp message from admin to user
intercom.messages.create({
  message_type: 'inapp',
  body: "What's up :)",
  from: {
    type: 'admin',
    id: "1234"
  },
  to: {
    type: "user",
    user_id: "5678"
  }
})

# Email message from admin to user
intercom.messages.create({
  message_type: 'email',
  subject: 'Hey there',
  body: "What's up :)",
  template: "plain", # or "personal",
  from: {
    type: "admin",
    id: "1234"
  },
  to: {
    type: "user",
    id: "536e564f316c83104c000020"
  }
})

# Message from a user
intercom.messages.create({
  from: {
    type: "user",
    id: "536e564f316c83104c000020"
  },
  body: "halp"
})

# Message from admin to contact

intercom.messages.create({
  body: "How can I help :)",
  from: {
    type: "admin",
    id: "1234"
  },
  to: {
    type: "contact",
    id: "536e5643as316c83104c400671"
  }
})

# Message from a contact
intercom.messages.create({
  from: {
    type: "contact",
    id: "536e5643as316c83104c400671"
  },
  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

# Find access token owner (only with Personal Access Token and OAuth)
intercom.admins.me
# Find an admin by id
intercom.admins.find(id: admin_id)
# Iterate over all admins
intercom.admins.all.each {|admin| puts admin.email }

Teams

# Find a team by id
intercom.teams.find(id: team_id)
# Iterate over all teams
intercom.teams.all.each {|team| puts team.name }

Counts

# App-wide counts
intercom.counts.for_app

# Users in segment counts
intercom.counts.for_type(type: 'user', count: 'segment')

Subscriptions

Subscribe to events in Intercom to receive webhooks.

# create a subscription
intercom.subscriptions.create(url: "http://example.com", topics: ["user.created"])

# fetch a subscription
intercom.subscriptions.find(id: "nsub_123456789")

# delete a subscription
subscription = intercom.subscriptions.find(id: "nsub_123456789")
intercom.subscriptions.delete(subscription)

# list subscriptions
intercom.subscriptions.all

Subscription Types

List all the subscription types that a contact can opt in to

# fetch a subscription
intercom.subscription_types.find(id: "1")

intercom.subscription_types.all

Articles

# 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

# 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

# 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)

Phone Call Redirect (switch)

# Create a redirect
redirect = intercom.phone_call_redirect.create(phone_number: "+353871234567")

Data Content Export

# Create a data export
export = intercom.export_content.create(created_at_after: 1667566801, created_at_before: 1668085202)


#View a data export
export = intercom.export_content.find(id: 'k0e27ohsyvh8ef3m')

# Cancel a data export
export = intercom.export_content.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.

You do not need to deal with the HTTP response from an API call directly. If there is an unsuccessful response then an error that is a subclass of Intercom::IntercomError will be raised. If desired, you can get at the http_code of an Intercom::IntercomError via its http_code method.

The list of different error subclasses are listed below. As they all inherit off Intercom::IntercomError you can choose to rescue Intercom::IntercomError or else rescue the more specific error subclass.

Intercom::AuthenticationError
Intercom::ServerError
Intercom::ServiceUnavailableError
Intercom::ServiceConnectionError
Intercom::ResourceNotFound
Intercom::BlockedUserError
Intercom::BadRequestError
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

Calling your client's rate_limit_details returns a Hash that contains details about your app's current rate limit.

intercom.rate_limit_details
#=> {:limit=>180, :remaining=>179, :reset_at=>2014-10-07 14:58:00 +0100}

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.

intercom = Intercom::Client.new(token: ENV['AT'], handle_rate_limit: true)

Pull Requests

  • Add tests! Your patch won't be accepted if it doesn't have tests.

  • Document any change in behaviour. Make sure the README and any other relevant documentation are kept up-to-date.

  • Create topic branches. Don't ask us to pull from your master branch.

  • One pull request per feature. If you want to do more than one thing, send multiple pull requests.

  • Send coherent history. Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before sending them to us.

Development

Running tests

# all tests
bundle exec rake spec

# unit tests
bundle exec rake spec:unit

# integration tests
bundle exec rake spec:integration

# single test file
bundle exec m spec/unit/intercom/job_spec.rb

# single test
bundle exec m spec/unit/intercom/job_spec.rb:49

intercom-ruby's People

Contributors

aidanf avatar apassant avatar benmcredmond avatar bobjflong avatar brianp avatar choran avatar claytonpassmore avatar conorkeating avatar darragh avatar dehora avatar erskingardner avatar eugeneius avatar finnlawrence avatar jkeyes avatar jonnyom avatar josler avatar kdaigle avatar khalilovcmd avatar mmartinic avatar murtron avatar nurazem avatar pocke avatar rahulgdsouza avatar reidab avatar ruairik avatar seanhealy33 avatar suma-prakash avatar theandrewykim avatar timcraft avatar wakematta avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

intercom-ruby's Issues

impression.rb methods don't match documentation

Not sure which is correct but impression.rb doesn't have the following documented methods:

user_id: required (if no email) โ€” a unique identifier for the user
current_url: optional โ€” The current url of the user

The user_id method is missing and the current_url method seems to be replaced by location in this release.

No configuration settings for secure mode

I'd like the intercom library to have a configuration setting for secure mode (e.g. Intercom.secret_key = 'abcdef0123') and either a utility function for doing the hashing, or for the library to handle it automatically.

Ruby 1.9.3 support

I was happy to see the new changes in the latest version of the API so I went and tried to update the gem and I discovered the gem doesn't support Ruby 1.9.3 any longer.

Are you planning to keep that limitation? Our app is still running on Ruby 1.9.3.

Thanks!

PS: maybe adding a note about this to the "Upgrading information" in the README would be helpful.

"Undefined method" error when fetching API resources

NoMethodError
undefined method `each' for nil:NilClass

Stacktrace (most recent call first):

  intercom/traits/api_resource.rb:26:in `from_hash'
    hash.each do |attribute, value|
  intercom/traits/api_resource.rb:20:in `from_response'
    from_hash(response)
  intercom/traits/api_resource.rb:113:in `from_api'
    object.from_response(api_response)
  intercom/api_operations/find.rb:13:in `find'
    from_api(response)

This is from a call to Intercom::Company.find(:company_id => xxxx), using version 2.1.3 of the gem.

This has only happened twice in the past month or so that our background job has been exporting to Intercom.

Support tagging by user_id and email

Intercom::Tag.tag_users only accepts the id field for a user. This means users typically have to be fetched before they can be tagged. We should surface the tag by email and user_id options that are available in the HTTP API.

Fail gracefully

For some of the actions like Find and others, when nothing matching is found, the gem throws and expection .. but as a general practice in ruby, i think it makes more sense to return a nil, so the failure can be graceful and developer can handle the special case when return object is nil.

`ServiceUnavailableIssue` is not provided an argument

From here https://github.com/intercom/intercom-ruby/blob/master/lib/intercom/request.rb#L71.

Initialize method is here https://github.com/intercom/intercom-ruby/blob/master/lib/intercom/errors.rb#L6.

Example trace:

vendor/bundle/ruby/2.0.0/gems/intercom-2.1.2/lib/intercom/errors.rb:6:in initialize
    from vendor/bundle/ruby/2.0.0/gems/intercom-2.1.2/lib/intercom/request.rb:71:in exception
    from vendor/bundle/ruby/2.0.0/gems/intercom-2.1.2/lib/intercom/request.rb:71:in raise
    from vendor/bundle/ruby/2.0.0/gems/intercom-2.1.2/lib/intercom/request.rb:71:in rescue in execute
    from vendor/bundle/ruby/2.0.0/gems/intercom-2.1.2/lib/intercom/request.rb:58:in execute
    from vendor/bundle/ruby/2.0.0/gems/intercom-2.1.2/lib/intercom.rb:83:in send_request_to_path
    from vendor/bundle/ruby/2.0.0/gems/intercom-2.1.2/lib/intercom.rb:112:in post
    from vendor/bundle/ruby/2.0.0/gems/intercom-2.1.2/lib/intercom/api_operations/save.rb:24:in save
    from vendor/bundle/ruby/2.0.0/gems/intercom-2.1.2/lib/intercom/api_operations/save.rb:11:in create

update_last_request_at should take boolean

Running Intercom::User.create(user_id:325, update_last_request_at:true) results in

NoMethodError: undefined method `to_i' for true:TrueClass
from (eval):4:in `update_last_request_at='

However running it as Intercom::User.create(user_id:325, update_last_request_at:1) works as expected.

Inconsistent behavior in string vs symbol parameters

I discovered this issue when I noticed that the following fails:

Intercom::Message.create(from: { 'type' => "user", 'email' => "[email protected]" }, body: "halp")

but this does not:

Intercom::Message.create(from: { type: "user", email: "[email protected]" }, body: "halp")

After some poking around I discovered this line:

@object_type ||= json['type']

From what I can tell, the first request is finding the 'type' (string) key and is turning from into an Intercom::User object. This then tries to serialize to an id instead of an email which causes the requests to fail.

The code should be modified to:

  1. Treat both symbols and strings the same here.
  2. Allow user messages to be sent with only an email as specified in the API.

User Avatar: bad 'avatar' parameter

According to http://doc.intercom.io/api/#users
I try to add an avatar to my users when they update their profile.

But, when I save tu Intercom User, I have this error : 'bad 'avatar' parameter'

In my update method I call my Intercom update :

  user.avatar = {
    :type => "avatar",
    :image_url => u.avatar.to_s
  }

I also tried

  # user.avatar.type = "avatar"
  # user.avatar.image_url = u.avatar.to_s

When I

  user.save

the error comes out. (Only in the first case, in the second nothing append and image_url stays at nil)
What I've done wrong ?

Client library falls over when API does not return JSON

In certain situations it seems the client tries to parse HTML error pages as JSON, which causes a JSON::ParserError to be thrown. Would it be possible for the client library to throw a "friendlier" error such as ServiceTemporarilyUnavailable? This would give us a better understanding of what's going on.

Alternatively, it seems that the HTML page is sent along with a 500 HTTP status code, would it be possible for the library to detect this instead?

Using 2.1.6.

JSON::ParserError: 757: unexpected token at '<!DOCTYPE html>
<html>
<head>
  <meta name="robots" content="noindex, nofollow" />
  <title>We're sorry, but something went wrong (500)</title>
  <style type="text/css">
    body {
      background: #e0e0e0 url(/images/frowny-icon.png) no-repeat center 93px;
      color: #fff;
      font-family: "Helvetica Neue", Helvetica, Arial;
      font-size: 14px;
      line-height: 22px;
      margin: 0;
    }
    .nc_has_icon {
      display: inline-block;
      padding-left: 24px;
      position: relative;
    }
    .nc_has_icon:before {
      background-image: url(/images/icons-white-reversed-shadow.png);
      background-repeat: no-repeat;
      background-position: 0 0;
      display: inline-block;
      content: "&nbsp;";
      width: 24px;
      text-indent: -9999em;
      text-align: left;
      position: absolute;
      left: 0;
      top: 0;
    }
    .nc_has_info_icon:before {
      background-position: -11px -616px;
    }
    .cabbaged {
      color: #fff;
      font-weight: bold;
      text-shadow: 0 -1px 0 rbga(0,0,0,0.57);
      background-color: #7f7f7f;
      border-bottom: 1px solid #f0f0f0;
      padding: 16px 0 15px;
      text-align: center;
    }
    .contact_support {
      display: block;
      width: 100%;
      margin: 260px auto 0;
      text-align: center;
      color: #636D74;
    }
    .contact_support a, .contact_support a:hover {
      color: #636D74;
      text-decoration: underline;
    }
  </style>
</head>

<body>
  <div class="cabbaged">
    <span class="nc_has_icon nc_has_info_icon">There was a problem loading this page. Please contact us with details through Intercom, or by email at [email protected].</span>
  </div>
  <div class="contact_support">
    <p><strong>Have a question? Need help? Get in touch:</strong></p>
    <p>
      Email: <a href="mailto:[email protected]">[email protected]</a><br>
      Site status: <a href="https://twitter.com/intercomstatus">@intercomstatus</a><br>
    </p>
  </div>
  <!-- This file lives in public/500.htm...

Stacktrace:

Stacktrace (most recent call first):

  json/common.rb:155:in `parse'
    Parser.new(source, opts).parse
  json/common.rb:155:in `parse'
    Parser.new(source, opts).parse
  intercom/request.rb:64:in `block in execute'
    parsed_body = JSON.parse(decoded)
  net/http.rb:852:in `start'
    return yield(self)
  intercom/request.rb:60:in `execute'
    client(base_uri).start do |http|
  intercom.rb:83:in `send_request_to_path'
    request.execute(target_base_url)
  intercom.rb:112:in `post'
    send_request_to_path(Intercom::Request.post(path, payload_hash))
  intercom/api_operations/save.rb:24:in `save'
    response = Intercom.post("/#{collection_name}", to_submittable_hash.merge(identity_hash))

Make Intercom.app_id and api_key readable

For my Rails application, it would be nice if I could set Intercom.app_id = 'abcdefghi' and then reference it from all of my code that uses the API

Currently, I just do Intercom.instance_variable_get('@app_id'), but it feels like I'm cheating.

Encoding::InvalidByteSequenceError: "\xC3" on US-ASCII

Hello:

I'm having this error:
Encoding::InvalidByteSequenceError: "\xC3" on US-ASCII from /opt/rbenv/versions/2.1.2/lib/ruby/2.1.0/json/common.rb:155:in encode'`

When I try to retrieve companies that their names contain accents (for example: ร‰lan) or create them using either:
Intercom::Company.find(company_id: id)
or
Intercom::Company.create(company_id: id, name: name, created_at: created_at)

I think the issue is the encoding in the body returned in the response, because the error is thrown when the JSON.parse is called to parse the decoded body

parsed_body = JSON.parse(decoded_body)

Thanks :)

Users containing special characters in their data causing encoding error

Trying to send data throws this error:

[11] IntercomApp (UNK)> Intercom::User.create(:name => "Bรธbbรฅ Gรผntร l", :email => "[email protected]", :created_at => Time.now)
Encoding::UndefinedConversionError: "\xC3" from ASCII-8BIT to UTF-8
from /Users/jeff/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/gems/intercom-0.1.17/lib/intercom/request.rb:37:in `encode'
[12] IntercomApp (UNK)> name = "Bรธbbรฅ Gรผntร l"
=> "B\xC3\xB8bb\xC3\xA5 G\xC3\xBCnt\xC3\xA0l"
[13] IntercomApp (UNK)> name.encoding
=> #<Encoding:ASCII-8BIT>
[14] IntercomApp (UNK)> name.encode("UTF-8")
Encoding::UndefinedConversionError: "\xC3" from ASCII-8BIT to UTF-8
from (pry):14:in `encode'
[18] IntercomApp (UNK)> Intercom::User.create(:name => "Bรธbbรฅ Gรผntร l".force_encoding("UTF-8"), :email => "[email protected]", :created_at => Time.now)force_encoding("UTF-8"), :email => "[email protected]", :created_at => Time.now)
=> #<Intercom::User:0x007fdc0510bda8 @attributes={"name"=>"Bรธbbรฅ Gรผntร l", "email"=>"[email protected]", "created_at"=>1397831074, "intercom_id"=>"535135a3299c8b11ac000a8c", "user_id"=>nil, "last_impression_at"=>nil, "custom_data"=>{}, "session_count"=>0, "last_seen_ip"=>nil, "last_seen_user_agent"=>nil, "unsubscribed_from_emails"=>false, "company_ids"=>[], "vip_timestamp"=>nil}, @social_profiles=[], @location_data=nil>

Trying to receive data back from the API will trigger a similar error in JSON parsing.

Dynamic Accessor Issue

When I try to find a company (using the new 2.0), I get this:

[45] pry(main)> Intercom::Company.find(company_id: 403)
Intercom::AttributeNotSetError: 'each' called on Intercom::Faith but it has not been set an attribute or does not exist as a method
from /usr/local/lib/ruby/gems/2.1.0/gems/intercom-2.0.1/lib/intercom/lib/dynamic_accessors_on_method_missing.rb:24:in `define_accessors_or_call'```

Unexpected error on Event Creation

Trying to create events with the newest version of the gem and I am getting these.
This code worked previously under the older versions.

Intercom::UnexpectedError: The error of type '' is not recognized. It occurred with the message: missing data parameter and http_code: '400'. Please contact Intercom with these details.

Cannot create a user with a company that has custom_data set

Does the api allow sending custom_data for a company when creating a new user?

I receive this error:

This does not support nested data structures (key: custom_data, value: {:foo=>"bar"}

here is my code:

begin
  user = Intercom::User.new(
    email: identity.email, 
    created_at: identity.created_at, 
    name: identity.full_name
  )
  user.companies = [ {name: co.name, id: co.id, custom_data: { foo: 'bar' }}]
  user.save
rescue Exception => e
  Rails.logger.warn("ERROR: Failed to add user to intercom: #{e.message}")
  return nil
end

here is the relevant backtrace:

/usr/local/rvm/gems/ruby-1.9.3-p125@rpp_web_app/gems/intercom-0.2.3/lib/intercom/flat_store.rb:23:in `validate_key_and_value'
/usr/local/rvm/gems/ruby-1.9.3-p125@rpp_web_app/gems/intercom-0.2.3/lib/intercom/flat_store.rb:7:in `block in initialize'
/usr/local/rvm/gems/ruby-1.9.3-p125@rpp_web_app/gems/intercom-0.2.3/lib/intercom/flat_store.rb:6:in `each'
/usr/local/rvm/gems/ruby-1.9.3-p125@rpp_web_app/gems/intercom-0.2.3/lib/intercom/flat_store.rb:6:in `initialize'
/usr/local/rvm/gems/ruby-1.9.3-p125@rpp_web_app/gems/intercom-0.2.3/lib/intercom/user.rb:336:in `new'
/usr/local/rvm/gems/ruby-1.9.3-p125@rpp_web_app/gems/intercom-0.2.3/lib/intercom/user.rb:336:in `block in companies='
/usr/local/rvm/gems/ruby-1.9.3-p125@rpp_web_app/gems/intercom-0.2.3/lib/intercom/user.rb:336:in `collect'
/usr/local/rvm/gems/ruby-1.9.3-p125@rpp_web_app/gems/intercom-0.2.3/lib/intercom/user.rb:336:in `companies='
/var/www/rpp_web_app/current/lib/intercom_helpers.rb:20:in `add_user'

Threads order

Hi Guys,

Could you help me clarify something with getting message threads through Intercom API? The documentation at http://docs.intercom.io/api#getting_messages didn't mentions if it's possible to sort threads on their updated_at-attribute. Currently, it seems API pushing threads randomly, so I did the following to get threads ordered by updated at:

@threads = @threads.sort_by{|message|
(Date.today - message.updated_at.to_date).to_i
}

Let me show you threads before and after the sort:

Before sort:

596132, 2013-08-29
461569, 2013-08-15
432854, 2013-08-22
430877, 2013-08-22
422990, 2013-07-04
422988, 2013-07-03
399214, 2013-08-29
385069, 2013-06-19
382727, 2013-08-21
382672, 2013-08-21
120639, 2013-09-08
118678, 2013-08-22
118531, 2013-09-08
104536, 2013-09-09

After sort:

104536, 2013-09-09
118531, 2013-09-08
120639, 2013-09-08
399214, 2013-08-29
596132, 2013-08-29
118678, 2013-08-22
432854, 2013-08-22
430877, 2013-08-22
382727, 2013-08-21
382672, 2013-08-21
461569, 2013-08-15
422990, 2013-07-04
422988, 2013-07-03

Also, could you confirm that modifying an auto-message will modify the message's updated_at field?

Thank you,
Adam

API error handler has trouble with 503 response codes

Intercom::UnexpectedError: The error of type '' is not recognized. It occurred with the message: Sorry, the API service is temporarily unavailable and http_code: '503'. Please contact Intercom with these details.

Stacktrace (most recent call first):

  intercom/request.rb:114:in `raise_application_errors_on_failure'
    raise Intercom::UnexpectedError.new(message_for_unexpected_error_with_type(error_details, parsed_http_code), error_context)
  intercom/request.rb:65:in `block in execute'
    raise_application_errors_on_failure(parsed_body, response.code.to_i) if parsed_body['type'] == 'error.list'
  net/http.rb:852:in `start'
    return yield(self)
  intercom/request.rb:60:in `execute'
    client(base_uri).start do |http|
  intercom.rb:83:in `send_request_to_path'
    request.execute(target_base_url)
  intercom.rb:124:in `get'
    send_request_to_path(Intercom::Request.get(path, params))
  intercom/api_operations/find.rb:11:in `find'
    response = Intercom.get("/#{collection_name}", params)

This is from a Intercom::User.find(:user_id => xxx) call, using version 2.1.3 of the gem.

distinguish connect based timeouts vs read based timeouts

When you get a Timeout::Error it's not clear whether it's a timeout waiting on a response from the server (read timeout currently 30 seconds) or in opening a connection in the first place (open timeout is currently 10 seconds).

We should make a distinction somehow to make it easier to track down the root cause of an issues.

(an approach similar to http://stackoverflow.com/questions/2625549/how-to-tell-a-connect-timeout-error-from-a-read-timeout-error-in-rubys-nethtt should work)

Intercom::UnexpectedError: The error of type '' is not recognized. It occurred with the message: Unauthorized token and http_code: '401'. Please contact Intercom with these details.

I'm getting the above error when trying to send any commands to Intercom from my Rails console. I've configured a test app on Intercom, (which intercom-rails successfully posts to), but for some reason, intercom-ruby isn't working.

irb(main):009:0> Intercom::User.all.map {|user| user.email }

Intercom::UnexpectedError: The error of type '' is not recognized. It occurred with the message: Unauthorized token and http_code: '401'. Please contact Intercom with these details.
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/intercom-2.4.4/lib/intercom/request.rb:148:in `raise_application_errors_on_failure'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/intercom-2.4.4/lib/intercom/request.rb:90:in `parse_body'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/intercom-2.4.4/lib/intercom/request.rb:66:in `block in execute'
    from ~/.rbenv/versions/2.1.2/lib/ruby/2.1.0/net/http.rb:853:in `start'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/intercom-2.4.4/lib/intercom/request.rb:61:in `execute'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/intercom-2.4.4/lib/intercom.rb:95:in `send_request_to_path'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/intercom-2.4.4/lib/intercom.rb:136:in `get'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/intercom-2.4.4/lib/intercom/collection_proxy.rb:22:in `block in each'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/intercom-2.4.4/lib/intercom/collection_proxy.rb:18:in `loop'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/intercom-2.4.4/lib/intercom/collection_proxy.rb:18:in `each'
    from (irb):9:in `map'
    from (irb):9
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/railties-4.1.9/lib/rails/commands/console.rb:90:in `start'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/railties-4.1.9/lib/rails/commands/console.rb:9:in `start'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/railties-4.1.9/lib/rails/commands/commands_tasks.rb:69:in `console'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/railties-4.1.9/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
    from ~/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/railties-4.1.9/lib/rails/commands.rb:17:in `<top (required)>'
    from bin/rails:4:in `require'
    from bin/rails:4:in `<main>'irb(main):010:0>

The error implies an authentication error, but Intercom.app_id & Intercom.app_api_key are both set correctly using same details as IntercomRails (which is reporting users correctly).

irb(main):009:0> IntercomRails::Config.api_key == Intercom.app_api_key
=> true
irb(main):010:0> IntercomRails::Config.app_id == Intercom.app_id
=> true

Intercom::User.location_data returns empty hash

When I'm fetching user data and trying to get location_data for it, I'm getting empty hash in result. Using gem ver. 0.1.14 with Ruby 2.0.0p247
'''[1] pry(main)> u = Intercom::User.find(:user_id => "_")
=> #<Intercom::User:0x007f7dfc557518
@attributes=
{"intercom_id"=>"5
f",
"email"=>"m**m",
"user_id"=>"5**b",
"name"=>"M**
",
"created_at"=>1342597889,
"last_impression_at"=>1378459384,
"custom_data"=>
{**
},
"social_profiles"=>[],
"location_data"=>
{"city_name"=>"**
",
"continent_code"=>"_",
"country_name"=>"
",
"latitude"=>**
,
"longitude"=>_,
"postal_code"=>"",
"region_name"=>"
",
"timezone"=>"**
",
"country_code"=>"_"},
"session_count"=>860,
"last_seen_ip"=>"
",
"last_seen_user_agent"=> "**
",
"unsubscribed_from_emails"=>false}>
[2] pry(main)> u.location_data
=> {}'''

what are the changes in version 2?

the warning message and the readme don't explain what the changes are, only that the key needs to be configured differently.

if i am to understand that the gem's API has changed, then giving us only the information for setting the service api key and not what else to change is the worst thing you can do, because we will be able to get it running but our old code will blow up.

so please, tell us what the actual api change are :)

Intercom::Tag.find_by_name should not throw exception when tag is not found.

Returning nil is preferred. And even better, implement find_or_create

>> Intercom::Tag.find name:'Tag Name'
Intercom::ResourceNotFound: Intercom::ResourceNotFound
  ./vendor/bundle/ruby/2.0.0/gems/intercom-0.2.3/lib/intercom/request.rb:78:in `raise_errors_on_failure'
  ./vendor/bundle/ruby/2.0.0/gems/intercom-0.2.3/lib/intercom/request.rb:63:in `block in execute'
  /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/net/http.rb:852:in `start'
  ./vendor/bundle/ruby/2.0.0/gems/intercom-0.2.3/lib/intercom/request.rb:61:in `execute'
  ./vendor/bundle/ruby/2.0.0/gems/intercom-0.2.3/lib/intercom.rb:67:in `send_request_to_path'
  ./vendor/bundle/ruby/2.0.0/gems/intercom-0.2.3/lib/intercom.rb:108:in `get'
  ./vendor/bundle/ruby/2.0.0/gems/intercom-0.2.3/lib/intercom/tag.rb:44:in `find'
  ./(rib-auto):3:in `main'
>> Intercom::Tag.create name:'Tag Name'
=> #<Intercom::Tag:0x007fab6be9d0b8 @name="Tag Name", @id=15876, @tagged_user_count=0>
>> Intercom::Tag.find name:'Tag Name'
=> #<Intercom::Tag:0x007fab710e9c68 @name="Tag Name", @id=15876, @tagged_user_count=0>

Undefined method `from_api' when sending messages

Hi,

I'm playing with the new API for sending messages but I got this weird error:

irb(main):037:0> # Email message from admin to user
irb(main):038:0* Intercom::Message.create({
irb(main):039:2*   :message_type => 'email',
irb(main):040:2*   :subject  => 'This is a test',
irb(main):041:2*   :body     => "Testing new API",
irb(main):042:2*   :template => "plain",
irb(main):043:2*   :from => {
irb(main):044:3*     :type => "admin",
irb(main):045:3*     :id   => MY_ADMIN_ID
irb(main):046:3>   },
irb(main):047:2*   :to => {
irb(main):048:3*     :type => "user",
irb(main):049:3*     :id => MY_USER_ID
irb(main):050:3>   }
irb(main):051:2> })
log writing failed. "\x8B" from ASCII-8BIT to UTF-8
NoMethodError: undefined method `from_api' for #<Class:0x007ff203716e00>
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/attr_encrypted-1.3.2/lib/attr_encrypted.rb:258:in `method_missing'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/activerecord-3.2.13/lib/active_record/dynamic_matchers.rb:55:in `method_missing'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/attr_encrypted-1.3.2/lib/attr_encrypted/adapters/active_record.rb:75:in `method_missing_with_attr_encrypted'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/intercom-2.0.3/lib/intercom/lib/typed_json_deserializer.rb:39:in `deserialize_object'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/intercom-2.0.3/lib/intercom/lib/typed_json_deserializer.rb:19:in `deserialize'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/intercom-2.0.3/lib/intercom/traits/api_resource.rb:71:in `set_property'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/intercom-2.0.3/lib/intercom/traits/api_resource.rb:62:in `initialize_property'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/intercom-2.0.3/lib/intercom/traits/api_resource.rb:28:in `block in from_hash'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/intercom-2.0.3/lib/intercom/traits/api_resource.rb:26:in `each'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/intercom-2.0.3/lib/intercom/traits/api_resource.rb:26:in `from_hash'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/intercom-2.0.3/lib/intercom/traits/api_resource.rb:20:in `from_response'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/intercom-2.0.3/lib/intercom/api_operations/save.rb:26:in `save'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/intercom-2.0.3/lib/intercom/api_operations/save.rb:11:in `create'
  from (irb):38
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
  from /Users/javi/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/gems/2.0.0/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
  from script/rails:6:in `require'
  from script/rails:6:in `<main>'irb(main):052:0>

Despite of this error, the message gets actually sent and I receive the email.

Intercom::Tag.tag_user fails silently, should be tag_users

Possible that I've done something stupid, as this isn't exactly a bug, but it was quite confusing to figure out what was going wrong. The api call on Intercom's side is tag_users with an s, but in the gem, Intercom::Tag.tag_user seems to work correctly, returning a Tag object, but not actually updating the user on Intercom.

Maybe a no method error would be helpful, or a behind the scenes switch to tag_users?

Real cause of error should be returned to the user

Trying to create a company with the following:

$ require 'intercom' 
$ Intercom.app_id = "app_id" 
$ Intercom.app_api_key = "api_key" 
$ Intercom::Company.create(:name => "Company Name")

Raises the following error

Intercom::UnexpectedError: The error of type '' is not recognized. It occurred with the message: Server Error and http_code: '500'. Please contact Intercom with these details. 

In this case the required company_id key/value is missing and that should be returned to the client in order to inform the user of their error.

Create/Update with Location Data fails

  • Gem Version: intercom (2.4.1)
  • Ruby Version : ruby 2.0.0p481 (2014-05-08 revision 45883) [x86_64-linux]

Use Case

Migration of data from MixPanel to Intercom

Expected Behaviour

Record is updated mapping MixPanel [city, timezone, region] to intercom equivalents. Or in the basic case, the Location Object for that user is updated.

Actual Behaviour

When location_data is offered by means of Intercom::User.create(.. :location_data => { .. } ..) request fails with

usr/local/share/ruby/gems/2.0/gems/intercom-2.4.1/lib/intercom/request.rb:137:in `raise_application_errors_on_failure': bad 'location_data' parameter (Intercom::BadRequestError)
    from /usr/local/share/ruby/gems/2.0/gems/intercom-2.4.1/lib/intercom/request.rb:90:in `parse_body'
    from /usr/local/share/ruby/gems/2.0/gems/intercom-2.4.1/lib/intercom/request.rb:66:in `block in execute'
    from /usr/share/ruby/2.0/net/http.rb:852:in `start'
    from /usr/local/share/ruby/gems/2.0/gems/intercom-2.4.1/lib/intercom/request.rb:61:in `execute'
    from /usr/local/share/ruby/gems/2.0/gems/intercom-2.4.1/lib/intercom.rb:95:in `send_request_to_path'
    from /usr/local/share/ruby/gems/2.0/gems/intercom-2.4.1/lib/intercom.rb:124:in `post'
    from /usr/local/share/ruby/gems/2.0/gems/intercom-2.4.1/lib/intercom/api_operations/save.rb:24:in `save'
    from /usr/local/share/ruby/gems/2.0/gems/intercom-2.4.1/lib/intercom/api_operations/save.rb:11:in `create'
    from import-intercom.rb:21:in `block in <main>'
    from import-intercom.rb:18:in `each'
    from import-intercom.rb:18:in `<main>'

Sample Code

user = Intercom::User.create(
                :email => properties["$email"],
                :name => "#{properties["$first_name"]} #{properties["$middle_name"]} #{properties["$last_name"]}",
                :user_id => record["$distinct_id"],
                :created_at => t_parse(properties["Signed Up"]),
                :remote_created_at => t_parse(properties["Signed Up"]),
                :location_data => {
                   # :timezone => properties["$timezone"],
                   # :region_name => properties["$region"],
                   #  :city_name => properties["$city"],
                   :city_name => 'Dublin',
                   :region_name => 'Leinster'
                },
                :last_request_at => t_parse(properties["$last_seen"]),
                :custom_attributes => {
                   :gender => properties["Gender"],
                   :date_of_birth => t_parse(properties["Date Of Birth"]),
                   :location => properties["Location"],
                   :client_os => properties["Client OS"],
                   :client_language => properties["Client Language"],
                   :device => properties["Client Device"],
                   :followers => properties["Followers"],
                   :following => properties["Following"],
                   :connected_native => properties["Connected Native"],
                   :connected_spotify => properties["Connected Spotify"],
                   :connected_youtube => properties["Connected Rdio"],
                   :connected_desktop => properties["Connected Desktop"],
                   :connected_pandora => properties["Connected Pandora"],
                   :connected_deezer => properties["Connected Deezer"],
                   :connected_8tracks => properties["Connected 8Tracks"],
                   :connected_soundcloud => properties["Connected Soundcloud"],
                   :connected_rdio => properties["Connected Rdio"],
                   :google_linked => properties["Linked Google"],
                   :twitter_linked => properties["Linked To Twitter"],
                   :facebook_linked => properties["Linked Facebook"],
                   :facebook_token_valid => properties["Facebook Token Valid"]
                }
    )

Sample User

I'm trying to execute a create/update on https://app.intercom.io/apps/gkrv0mwf/users/54634f155df18a53a5000a81 as an example

Interesting to note that if I remove the location data parameter, the create/update works.

Testing and intercom-ruby

Is there any good way to test your application whilst using intercom-ruby, without disabling it completely in the test environment (which I don't want to do for obvious reasons)?

It would be great if there was some way to have a separate sandbox area in Intercom for data created through tests. The only way I can see this working at the moment is to create a separate dummy Intercom account to use for testing?

The error of type '' is not recognized.

Intercom::Conversation.find_all(type: 'admin').each {|convo| p convo }

=>

Intercom::UnexpectedError: The error of type '' is not recognized. It occurred with the message: The API request [ https://api.intercom.io/conversations?type=admin&id=7] is not available on your current plan [unknown]. and http_code: '402'. Please contact Intercom with these details.

I get an exception when I increment

If i fetch a user and try to increment a field, I get an exception.

user = Intercom::User.find(:user_id => "1")
user.increment('karma'); user.save

exception:

Intercom::BadRequestError: bad 'increments' parameter
from /app/vendor/bundle/ruby/2.1.0/gems/intercom-2.1.0/lib/intercom/request.rb:106:in `raise_application_errors_on_failure'
from /app/vendor/bundle/ruby/2.1.0/gems/intercom-2.1.0/lib/intercom/request.rb:65:in `block in execute'
from /app/vendor/ruby-2.1.2/lib/ruby/2.1.0/net/http.rb:853:in `start'
from /app/vendor/bundle/ruby/2.1.0/gems/intercom-2.1.0/lib/intercom/request.rb:60:in `execute'
from /app/vendor/bundle/ruby/2.1.0/gems/intercom-2.1.0/lib/intercom.rb:83:in `send_request_to_path'
from /app/vendor/bundle/ruby/2.1.0/gems/intercom-2.1.0/lib/intercom.rb:112:in `post'
from /app/vendor/bundle/ruby/2.1.0/gems/intercom-2.1.0/lib/intercom/api_operations/save.rb:24:in `save'
from (irb):6
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.2/lib/rails/commands/console.rb:90:in `start'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.2/lib/rails/commands/console.rb:9:in `start'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.2/lib/rails/commands/commands_tasks.rb:69:in `console'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.2/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.2/lib/rails/commands.rb:17:in `<top (required)>'
from /app/bin/rails:4:in `require'
from /app/bin/rails:4:in `<main>'

License missing from gemspec

RubyGems.org doesn't report a license for your gem. This is because it is not specified in the gemspec of your last release.

via e.g.

spec.license = 'MIT'
# or
spec.licenses = ['MIT', 'GPL-2']

Including a license in your gemspec is an easy way for rubygems.org and other tools to check how your gem is licensed. As you can imagine, scanning your repository for a LICENSE file or parsing the README, and then attempting to identify the license or licenses is much more difficult and more error prone. So, even for projects that already specify a license, including a license in your gemspec is a good practice. See, for example, how rubygems.org uses the gemspec to display the rails gem license.

There is even a License Finder gem to help companies/individuals ensure all gems they use meet their licensing needs. This tool depends on license information being available in the gemspec. This is an important enough issue that even Bundler now generates gems with a default 'MIT' license.

I hope you'll consider specifying a license in your gemspec. If not, please just close the issue with a nice message. In either case, I'll follow up. Thanks for your time!

Appendix:

If you need help choosing a license (sorry, I haven't checked your readme or looked for a license file), GitHub has created a license picker tool. Code without a license specified defaults to 'All rights reserved'-- denying others all rights to use of the code.
Here's a list of the license names I've found and their frequencies

p.s. In case you're wondering how I found you and why I made this issue, it's because I'm collecting stats on gems (I was originally looking for download data) and decided to collect license metadata,too, and make issues for gemspecs not specifying a license as a public service :). See the previous link or my blog post about this project for more information.

Find user by email when there are multiple users with same email has bad error message

The error message said to tell you about it, so here you are:

Intercom::UnexpectedError: The error of type '' is not recognized. It occurred with the message: Multiple existing users match this email address - must be more specific using user_id and http_code: '400'. Please contact Intercom with these details.
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom/request.rb:118:in `raise_application_errors_on_failure'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom/request.rb:65:in `block in execute'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom/request.rb:60:in `execute'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom.rb:83:in `send_request_to_path'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom.rb:124:in `get'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom/api_operations/find.rb:11:in `find'
/Users/pas/code/cloudnative/bakery/lib/tasks/intercom.rake:52:in `rescue in block (3 levels) in <top (required)>'
/Users/pas/code/cloudnative/bakery/lib/tasks/intercom.rake:47:in `block (3 levels) in <top (required)>'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/activerecord-4.1.6/lib/active_record/relation/delegation.rb:46:in `each'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/activerecord-4.1.6/lib/active_record/relation/delegation.rb:46:in `each'
/Users/pas/code/cloudnative/bakery/lib/tasks/intercom.rake:41:in `block (2 levels) in <top (required)>'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/bin/ruby_executable_hooks:15:in `eval'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/bin/ruby_executable_hooks:15:in `<main>'
Intercom::ResourceNotFound: User Not Found
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom/request.rb:110:in `raise_application_errors_on_failure'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom/request.rb:65:in `block in execute'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom/request.rb:60:in `execute'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom.rb:83:in `send_request_to_path'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom.rb:124:in `get'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/intercom-2.1.6/lib/intercom/api_operations/find.rb:11:in `find'
/Users/pas/code/cloudnative/bakery/lib/tasks/intercom.rake:48:in `block (3 levels) in <top (required)>'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/activerecord-4.1.6/lib/active_record/relation/delegation.rb:46:in `each'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/gems/activerecord-4.1.6/lib/active_record/relation/delegation.rb:46:in `each'
/Users/pas/code/cloudnative/bakery/lib/tasks/intercom.rake:41:in `block (2 levels) in <top (required)>'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/bin/ruby_executable_hooks:15:in `eval'
/Users/pas/.rvm/gems/ruby-2.1.2@cyan19/bin/ruby_executable_hooks:15:in `<main>'

I get that finding a user by email when email is no unique fails. This issue is just to let you know this can happen.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.