Skip to content

anibalcucco/basecamp-wrapper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

61 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

A Ruby library for working with the Basecamp web-services API.

For more information about the Basecamp web-services API, visit:

http://developer.37signals.com/basecamp

You can find the original code in:

http://developer.37signals.com/basecamp/basecamp.rb

NOTE: not all of Basecamp’s web-services are accessible via REST. This library provides access to RESTful services via ActiveResource. Services not yet upgraded to REST are accessed via the Basecamp class. Continue reading for more details.

Installation

Install the gem

gem install basecamp

Include the system gems and require the library in your script

require 'rubygems'
require 'basecamp'

Dependencies

* activeresource >= 2.3.0
* xml-simple
* oauth2

Establishing a Connection

The first thing you need to do is establish a connection to Basecamp. This requires your Basecamp site address and your login credentials or API token.

Using username and password

Basecamp.establish_connection!('yoururl.basecamphq.com', 'username', 'password')

Using API token (My Info -> Show your tokens)

Basecamp.establish_connection!('yoururl.basecamphq.com', 'APITOKEN', 'X')

Using OAuth access token

Basecamp.establish_oauth_connection!('yoururl.basecamphq.com', 'oauth_access_token')

Using SSL/Non SSL basecamp accounts (yoururl.basecamphq.com)

Basecamp uses SSL in all accounts so that’s the default value here for establish_connection!. This will use https for the connection:

Basecamp.establish_connection!('yoururl.basecamphq.com', 'APITOKEN', 'X')

Basecamp.establish_oauth_connection!('yoururl.basecamphq.com', 'oauth_access_token')

But if for some reason your basecamp account doesn’t use SSL, you can disable with:

Basecamp.establish_connection!('yoururl.basecamphq.com', 'APITOKEN', 'X', false)

Basecamp.establish_oauth_connection!('yoururl.basecamphq.com', 'oauth_access_token', false)

This is the same whether you’re accessing using the ActiveResource interface, or the legacy interface.

Using the REST interface via ActiveResource

The REST interface is accessed via ActiveResource, a popular Ruby library that implements object-relational mapping for REST web-services. For more information on working with ActiveResource, see:

* http://api.rubyonrails.org/files/activeresource/README.html
* http://api.rubyonrails.org/classes/ActiveResource/Base.html

Basecamp API rate limit and app identification

If your app creates a lot of requests, you may hit the (new) basecamp rate limit. (read more here about rate limiting).

To raise your limit you can send a custom user-agent to basecamp with your identifying information (read more here).

For this you need to create an initializer in your rails application, for example: config/inititalizer/basecamp_user_agent.rb with the following line:

ActiveResource::Base.headers["User-Agent"] = "Fabian's Ingenious Integration (fabian@example.com)"

This initializer ensures that all requests made through ActiveResource (which this gem uses) are identifiable with your information.

NOTE: If you are using ActiveResource for accessing multiple APIs at once and not only basecamp’s, you will need the following initializer instead:

Basecamp::Resource.headers["User-Agent"] = "Fabian's Ingenious Integration (fabian@example.com)"

Finding a Resource

Find a specific resource using the find method. Attributes of the resource are available as instance methods on the resulting object. For example, to find a message with the ID of 8675309 and access its title attribute, you would do the following:

m = Basecamp::Message.find(8675309)
m.title # => 'Jenny'

To find all messages for a given project, use find(:all), passing the project_id as a parameter to find. Example:

messages = Basecamp::Message.find(:all, params => { :project_id => 1037 })
messages.size # => 25

To get the current logged in user:

Basecamp::Person.me

Note: You can access the API token using this object. This is useful if you only have username/password and you want to use the API token in future calls:

Basecamp::Person.me.token

To get all people by company:

Basecamp::Person.find(:all, :params => {:company_id => company.id})

To get all people by project:

Basecamp::Person.find(:all, :params => {:project_id => project.id})

Creating a Resource

Create a resource by making a new instance of that resource, setting its attributes, and saving it. If the resource requires a prefix to identify it (as is the case with resources that belong to a sub-resource, such as a project), it should be specified when instantiating the object. Examples:

m = Basecamp::Message.new(:project_id => 1037)
m.category_id = 7301
m.title = 'Message in a bottle'
m.body = 'Another lonely day, with no one here but me'
m.save # => true

c = Basecamp::Comment.new(:post_id => 25874)
c.body = 'Did you get those TPS reports?'
c.save # => true

You can also create a resource using the create method, which will create and save it in one step. Example:

Basecamp::TodoItem.create(:todo_list_id => 3422, :contents => 'Do it')

Updating a Resource

To update a resource, first find it by its id, change its attributes, and save it. Example:

m = Basecamp::Message.find(8675309)
m.body = 'Changed'
m.save # => true

Deleting a Resource

To delete a resource, use the delete method with the ID of the resource you want to delete. Example:

Basecamp::Message.delete(1037)

Attaching Files to a Resource

If the resource accepts file attachments, the attachments parameter should be an array of Basecamp::Attachment objects. Example:

f1 = File.open('primary.doc')
s1 = StringIO.new('a string')

a1 = Basecamp::Attachment.create('primary', f1)
a2 = Basecamp::Attachment.create('another', s1))

m = Basecamp::Message.new(:project_id => 1037)
...
m.attachments = [a1, a2]
m.save # => true

f1.close

Milestones

Is not implemented as an active resource, it uses the non-REST interface. Browse the source (lib/basecamp/resources/milestone) to see all available methods.

For example, to list all milestones in a project:

milestones = Basecamp::Milestone.list(1037)
milestones.first.title # => "The Milestone"

More about Todo Items

To access all todo items in a todo list:

Basecamp::TodoItem.find(:all, :params => { :todo_list_id => 3422 })

You can’t access all todo items in a project with a single API call. So you have to do something like this:

def todo_items_on_project(project_id)
  todo_items = []
  todo_lists = TodoList.find(:all, :params => { :project_id => project_id })
  todo_lists.each do |todo_list|
    todo_items += TodoItem.find(:all, :params => { :todo_list_id => todo_list.id })
  end
  todo_items
end

Time entries

There are two ways to create time-entries

# TodoItem as Parent Resource
Basecamp::TimeEntry.create(:todo_item_id => item_id, :date => date, :person_id => person_id, :hours => hours, :description => '')
# Project as Parent Resource
  Basecamp::TimeEntry.create(:project_id => project_id, :date => date, :person_id => person_id, :hours => hours, :description => '')

Using the non-REST interface

You can access other resources not included in this wrapper yet using “record” and “records”.

person = Basecamp.record("/contacts/person/93832")
person.first_name # => "Jason"

people_in_company = Basecamp.records("person", "/contacts/people/85")
people_in_company.first.first_name # => "Jason"

Using json as the default format

By default the wrapper will use :xml for the active record connection but you can set :json as the default format:

Basecamp.establish_connection!('yoururl.basecamphq.com', 'APITOKEN', 'X', true, false)

Note: We recommend using xml. There are some API calls that don’t behave well with json.

Access active resource response object

You can acces the last response object:

Basecamp::Message.find(:all, params => { :project_id => 1037 })
Basecamp::Message.connection.response["status"] # => "200 OK"

Using the raw response body

This is useful for example to get pagination data to access all comments in a commentable resource: github.com/37signals/basecamp-classic-api/blob/master/sections/comments.md#get-recent-comments-for-a-commentable-resource

def get_threshold
  # Get the last response object
  response = Basecamp::Comment.connection.response
  # Parse the xml
  xml = XmlSimple.xml_in(response.body)
  # continued-at is an attribute specifying the path where the next oldest 75 comments can be retrieved
  if continued_at = xml["continued-at"]
    # There are more comments
    # We need to extract the threshold parameter from the continued-at url
    hash = CGI::parse(URI.parse(continued_at).query)
    hash["threshold"].first
  else
    # We're done
    nil
  end
end

comments = Basecamp::Comment.find(:all, :params => { :post_id => 1037 })
if threshold = get_threshold
  # Get the next set of comments using the threshold
  Basecamp::Comment.find(:all, :params => { :post_id => 1037, :threshold => threshold })
end

Contributors

  • jamesarosen

  • defeated

  • justinbarry

  • fmiopensource