Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Configurable client #42

Merged
merged 10 commits into from

2 participants

Ross Kaffenberger Jeremy Tregunna
Ross Kaffenberger

This pull request introduces a configuration DSL typical of other API clients for setting up authorization.

Basic authorization

Trello.configure do |config|
  config.developer_public_key = TRELLO_DEVELOPER_PUBLIC_KEY
  config.member_token = TRELLO_MEMBER_TOKEN
end

2-legged OAuth authorization

Trello.configure do |config|
  config.consumer_key = TRELLO_CONSUMER_KEY
  config.consumer_secret = TRELLO_CONSUMER_SECRET
  config.oauth_token = TRELLO_OAUTH_TOKEN
  config.oauth_token_secret = TRELLO_OAUTH_TOKEN_SECRET
end

3-legged OAuth authorization

Trello.configure do |config|
  config.consumer_key    = TRELLO_CONSUMER_KEY
  config.consumer_secret = TRELLO_CONSUMER_SECRET
  config.return_url      = "http://your.site.com/path/to/receive/post"
  config.callback        = lambda { |request_token| DB.save(request_token.key, request_token.secret) }
end

The current convention of setting OAuthCredential.consumer_credential etc. is still supported though I'd like to see it deprecated.

I believe this approach would make it easier to get up and running and may be a good solution to the ideas suggested previously https://trello.com/c/zmmvPD3k.

Jeremy Tregunna

Can you update this pull request so that it'll merge cleanly? I'd love to merge this into the repo as soon as possible.

Ross Kaffenberger

Done. Thanks!

Jeremy Tregunna jeremytregunna merged commit d7fb81f into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 671 additions and 249 deletions.
  1. +33 −0 README.md
  2. +9 −9 Rakefile
  3. +26 −9 lib/trello.rb
  4. +3 −3 lib/trello/action.rb
  5. +105 −49 lib/trello/authorization.rb
  6. +10 −2 lib/trello/basic_data.rb
  7. +4 −4 lib/trello/board.rb
  8. +17 −17 lib/trello/card.rb
  9. +3 −3 lib/trello/checklist.rb
  10. +48 −31 lib/trello/client.rb
  11. +51 −0 lib/trello/configuration.rb
  12. +1 −1  lib/trello/has_actions.rb
  13. +2 −2 lib/trello/list.rb
  14. +2 −2 lib/trello/member.rb
  15. +6 −6 lib/trello/notification.rb
  16. +2 −2 lib/trello/organization.rb
  17. +6 −6 spec/action_spec.rb
  18. +1 −0  spec/basic_auth_policy_spec.rb
  19. +16 −16 spec/board_spec.rb
  20. +28 −28 spec/card_spec.rb
  21. +3 −3 spec/checklist_spec.rb
  22. +22 −19 spec/client_spec.rb
  23. +114 −0 spec/configuration_spec.rb
  24. +1 −1  spec/integration/how_to_authorize_spec.rb
  25. +6 −6 spec/list_spec.rb
  26. +6 −6 spec/member_spec.rb
  27. +10 −10 spec/notification_spec.rb
  28. +55 −9 spec/oauth_policy_spec.rb
  29. +2 −2 spec/organization_spec.rb
  30. +3 −3 spec/token_spec.rb
  31. +76 −0 spec/trello_spec.rb
33 README.md
View
@@ -16,6 +16,39 @@ Seriously, [check it out](http://www.trello.com/).
Full Disclosure: This library is mostly complete, if you do find anything missing or not functioning as you expect it
to, please [let us know](https://trello.com/card/spot-a-bug-report-it/4f092b2ee23cb6fe6d1aaabd/17).
+## Configuration
+
+Basic authorization
+
+```ruby
+Trello.configure do |config|
+ config.developer_public_key = TRELLO_DEVELOPER_PUBLIC_KEY
+ config.member_token = TRELLO_MEMBER_TOKEN
+end
+```
+
+2-legged OAuth authorization
+
+```ruby
+Trello.configure do |config|
+ config.consumer_key = TRELLO_CONSUMER_KEY
+ config.consumer_secret = TRELLO_CONSUMER_SECRET
+ config.oauth_token = TRELLO_OAUTH_TOKEN
+ config.oauth_token_secret = TRELLO_OAUTH_TOKEN_SECRET
+end
+```
+
+3-legged OAuth authorization
+
+```ruby
+Trello.configure do |config|
+ config.consumer_key = TRELLO_CONSUMER_KEY
+ config.consumer_secret = TRELLO_CONSUMER_SECRET
+ config.return_url = "http://your.site.com/path/to/receive/post"
+ config.callback = lambda { |request_token| DB.save(request_token.key, request_token.secret) }
+end
+```
+
## Special thanks
A special thanks goes out to [Ben Biddington](https://github.com/ben-biddington) who has contributed a significant amount
18 Rakefile
View
@@ -4,7 +4,7 @@ RSpec::Core::RakeTask.new
task :default => [:spec]
-namespace :example do
+namespace :example do
require "addressable/uri"
require "trello"
include Trello
@@ -16,20 +16,20 @@ namespace :example do
@developer_public_key = ENV["DEVELOPER_PUBLIC_KEY"]
@developer_secret = ENV["DEVELOPER_SECRET"]
-
+
OAuthPolicy.consumer_credential = OAuthCredential.new @developer_public_key, @developer_secret
OAuthPolicy.token = nil
request = Request.new :get, URI.parse("https://trello.com/1/OAuthGetRequestToken")
response = TInternet.execute OAuthPolicy.authorize(request)
-
+
the_request_token = parse_token(response.body)
puts "key => #{the_request_token.key}, secret => #{the_request_token.secret}"
end
- desc "convert request token to access token"
- task :get_access_token, :request_token_key, :request_token_secret, :oauth_verifier do |t, args|
+ desc "convert request token to access token"
+ task :get_access_token, :request_token_key, :request_token_secret, :oauth_verifier do |t, args|
ensure_consumer_credentials
@developer_public_key = ENV["DEVELOPER_PUBLIC_KEY"]
@developer_secret = ENV["DEVELOPER_SECRET"]
@@ -39,17 +39,17 @@ namespace :example do
access_token_request = Request.new :get, URI.parse("https://trello.com/1/OAuthGetAccessToken?oauth_verifier=#{args.oauth_verifier}")
response = TInternet.execute OAuthPolicy.authorize(access_token_request)
-
+
the_access_token = parse_token response.body
-
+
puts "key => #{the_access_token.key}, secret => #{the_access_token.secret}"
end
def ensure_consumer_credentials
%w{PUBLIC_KEY SECRET}.each do |name|
fullname = "DEVELOPER_#{name}"
- unless ENV[fullname]
- puts "ERROR: Missing <#{fullname}> environment variable."
+ unless ENV[fullname]
+ puts "ERROR: Missing <#{fullname}> environment variable."
exit 1
end
end
35 lib/trello.rb
View
@@ -1,3 +1,4 @@
+
require 'oauth'
require 'json'
require 'logger'
@@ -7,20 +8,18 @@
#
# First, set up your key information. You can get this information by {clicking here}[https://trello.com/1/appKey/generate].
#
-# include Trello
-# include Trello::Authorization
-#
-# Trello::Authorization.const_set :AuthPolicy, OAuthPolicy
-#
-# OAuthPolicy.consumer_credential = OAuthCredential.new 'PUBLIC_KEY', 'SECRET'
-#
# You can get the key by going to this url in your browser:
-# https://trello.com/1/authorize?key=PUBLIC_KEY_FROM_ABOVE&name=MyApp&response_type=token&scope=read,write,account&expiration=never
+# https://trello.com/1/authorize?key=TRELLO_CONSUMER_KEY_FROM_ABOVE&name=MyApp&response_type=token&scope=read,write,account&expiration=never
# Only request the permissions you need; i.e., scope=read if you only need read, or scope=write if you only need write. Comma separate scopes you need.
# If you want your token to expire after 30 days, drop the &expiration=never. Then run the following code, where KEY denotes the key returned from the
# url above:
#
-# OAuthPolicy.token = OAuthCredential.new 'KEY', nil
+# Trello.configure do |config|
+# config.consumer_key = TRELLO_CONSUMER_KEY
+# config.consumer_secret = TRELLO_CONSUMER_SECRET
+# config.oauth_token = TRELLO_OAUTH_TOKEN
+# config.oauth_token_secret = TRELLO_OAUTH_TOKEN_SECRET
+# end
#
# All the calls this library make to Trello require authentication using these keys. Be sure to protect them.
#
@@ -47,6 +46,7 @@ module Trello
autoload :Card, 'trello/card'
autoload :Checklist, 'trello/checklist'
autoload :Client, 'trello/client'
+ autoload :Configuration, 'trello/configuration'
autoload :HasActions, 'trello/has_actions'
autoload :Item, 'trello/item'
autoload :CheckItemState, 'trello/item_state'
@@ -81,4 +81,21 @@ def self.logger
def self.logger=(logger)
@logger = logger
end
+
+ def self.client
+ @client ||= Client.new
+ end
+
+ def self.configure
+ reset!
+ yield client.configuration
+ end
+
+ def self.auth_policy
+ client.auth_policy
+ end
+
+ def self.reset!
+ @client = nil
+ end
end
6 lib/trello/action.rb
View
@@ -27,17 +27,17 @@ def update_fields(fields)
# Returns the board this action occurred on.
def board
- Client.get("/actions/#{id}/board").json_into(Board)
+ client.get("/actions/#{id}/board").json_into(Board)
end
# Returns the card the action occurred on.
def card
- Client.get("/actions/#{id}/card").json_into(Card)
+ client.get("/actions/#{id}/card").json_into(Card)
end
# Returns the list the action occurred on.
def list
- Client.get("/actions/#{id}/list").json_into(List)
+ client.get("/actions/#{id}/list").json_into(List)
end
# Returns the member who created the action.
154 lib/trello/authorization.rb
View
@@ -4,21 +4,34 @@
module Trello
module Authorization
- AuthPolicy = Class.new
+ AuthPolicy = Class.new do
+ def initialize(attrs = {}); end
+ end
class BasicAuthPolicy
class << self
attr_accessor :developer_public_key, :member_token
def authorize(request)
- the_uri = Addressable::URI.parse(request.uri)
- existing_values = the_uri.query_values.nil? ? {} : the_uri.query_values
- new_values = { :key => @developer_public_key, :token => @member_token }
- the_uri.query_values = new_values.merge existing_values
-
- Request.new request.verb, the_uri, request.headers, request.body
+ new.authorize(request)
end
end
+
+ attr_accessor :developer_public_key, :member_token
+
+ def initialize(attrs = {})
+ @developer_public_key = attrs[:developer_public_key] || self.class.developer_public_key
+ @member_token = attrs[:member_token] || self.class.member_token
+ end
+
+ def authorize(request)
+ the_uri = Addressable::URI.parse(request.uri)
+ existing_values = the_uri.query_values.nil? ? {} : the_uri.query_values
+ new_values = { :key => @developer_public_key, :token => @member_token }
+ the_uri.query_values = new_values.merge existing_values
+
+ Request.new request.verb, the_uri, request.headers, request.body
+ end
end
class Clock
@@ -57,60 +70,103 @@ class << self
attr_accessor :consumer_credential, :token, :return_url, :callback
def authorize(request)
- unless consumer_credential
- Trello.logger.error "The consumer_credential has not been supplied."
- fail "The consumer_credential has not been supplied."
- end
-
- if token
- request.headers = {"Authorization" => get_auth_header(request.uri, :get)}
- request
- else
- consumer(:return_url => return_url, :callback_method => :postMessage)
- request_token = consumer.get_request_token
- callback.call request_token
- return nil
- end
+ new.authorize(request)
end
+ end
- private
-
- def consumer_params(params = {})
- {
- :scheme => :header,
- :scope => 'read,write,account',
- :http_method => :get,
- :request_token_path => "https://trello.com/1/OAuthGetRequestToken",
- :authorize_path => "https://trello.com/1/OAuthAuthorizeToken",
- :access_token_path => "https://trello.com/1/OAuthGetAccessToken"
- }.merge!(params)
+ attr_accessor :attributes
+ attr_accessor :consumer_credential, :token, :return_url, :callback
+
+ def initialize(attrs = {})
+ @consumer_key = attrs[:consumer_key]
+ @consumer_secret = attrs[:consumer_secret]
+ @oauth_token = attrs[:oauth_token]
+ @oauth_token_secret = attrs[:oauth_token_secret]
+ @return_url = attrs[:return_url] || self.class.return_url
+ @callback = attrs[:callback] || self.class.callback
+ end
+
+ def authorize(request)
+ unless consumer_credential
+ Trello.logger.error "The consumer_credential has not been supplied."
+ fail "The consumer_credential has not been supplied."
end
- def consumer(options = {})
- @consumer ||= OAuth::Consumer.new(
- consumer_credential.key,
- consumer_credential.secret,
- consumer_params(options)
- )
+ if token
+ request.headers = {"Authorization" => get_auth_header(request.uri, :get)}
+ request
+ else
+ consumer(:return_url => return_url, :callback_method => :postMessage)
+ request_token = consumer.get_request_token
+ callback.call request_token
+ return nil
end
+ end
- def get_auth_header(url, verb, options = {})
- self.token ||= OAuththCredential.new
+ def consumer_credential
+ @consumer_credential ||= build_consumer_credential
+ end
- request = Net::HTTP::Get.new Addressable::URI.parse(url).to_s
+ def token
+ @token ||= build_token
+ end
+
+ def consumer_key; consumer_credential.key; end
+ def consumer_secret; consumer_credential.secret; end
+ def oauth_token; token.key; end
+ def oauth_token_secret; token.secret; end
- consumer.options[:signature_method] = 'HMAC-SHA1'
- consumer.options[:nonce] = Nonce.next
- consumer.options[:timestamp] = Clock.timestamp
- consumer.options[:uri] = url
- consumer.key = consumer_credential.key
- consumer.secret = consumer_credential.secret
+ private
- consumer.sign!(request, OAuth::Token.new(token.key, token.secret))
+ def build_consumer_credential
+ if @consumer_key && @consumer_secret
+ OAuthCredential.new @consumer_key, @consumer_secret
+ else
+ self.class.consumer_credential
+ end
+ end
- request['authorization']
+ def build_token
+ if @oauth_token
+ OAuthCredential.new @oauth_token, @oauth_token_secret
+ else
+ self.class.token
end
end
+
+ def consumer_params(params = {})
+ {
+ :scheme => :header,
+ :scope => 'read,write,account',
+ :http_method => :get,
+ :request_token_path => "https://trello.com/1/OAuthGetRequestToken",
+ :authorize_path => "https://trello.com/1/OAuthAuthorizeToken",
+ :access_token_path => "https://trello.com/1/OAuthGetAccessToken"
+ }.merge!(params)
+ end
+
+ def consumer(options = {})
+ @consumer ||= OAuth::Consumer.new(
+ consumer_credential.key,
+ consumer_credential.secret,
+ consumer_params(options)
+ )
+ end
+
+ def get_auth_header(url, verb, options = {})
+ request = Net::HTTP::Get.new Addressable::URI.parse(url).to_s
+
+ consumer.options[:signature_method] = 'HMAC-SHA1'
+ consumer.options[:nonce] = Nonce.next
+ consumer.options[:timestamp] = Clock.timestamp
+ consumer.options[:uri] = url
+ consumer.key = consumer_credential.key
+ consumer.secret = consumer_credential.secret
+
+ consumer.sign!(request, OAuth::Token.new(token.key, token.secret))
+
+ request['authorization']
+ end
end
end
end
12 lib/trello/basic_data.rb
View
@@ -8,7 +8,7 @@ class BasicData
class << self
def find(path, id)
- Client.get("/#{path}/#{id}").json_into(self)
+ client.get("/#{path}/#{id}").json_into(self)
end
end
@@ -55,12 +55,16 @@ def self.many(name, opts = {})
resource = options.delete(:in) || self.class.to_s.split("::").last.downcase.pluralize
klass = options.delete(:via) || Trello.const_get(name.to_s.singularize.camelize)
params = options.merge(args[0] || {})
- resources = Client.get("/#{resource}/#{id}/#{name}", params).json_into(klass)
+ resources = client.get("/#{resource}/#{id}/#{name}", params).json_into(klass)
MultiAssociation.new(self, resources).proxy
end
end
end
+ def self.client
+ Trello.client
+ end
+
register_attributes :id, :readonly => [ :id ]
def initialize(fields = {})
@@ -80,5 +84,9 @@ def refresh!
def ==(other)
id == other.id
end
+
+ def client
+ self.class.client
+ end
end
end
8 lib/trello/board.rb
View
@@ -21,7 +21,7 @@ def create(fields)
end
def all
- Client.get("/members/#{Member.find(:me).username}/boards").json_into(self)
+ client.get("/members/#{Member.find(:me).username}/boards").json_into(self)
end
end
@@ -32,7 +32,7 @@ def save
fields.merge!(:desc => description) if description
fields.merge!(:idOrganization => organization_id) if organization_id
- Client.post("/boards", fields).json_into(self)
+ client.post("/boards", fields).json_into(self)
end
def update!
@@ -41,7 +41,7 @@ def update!
@previously_changed = changes
@changed_attributes.clear
- Client.put("/boards/#{self.id}/", {
+ client.put("/boards/#{self.id}/", {
:name => attributes[:name],
:description => attributes[:description],
:closed => attributes[:closed]
@@ -68,7 +68,7 @@ def has_lists?
end
def find_card(card_id)
- Client.get("/boards/#{self.id}/cards/#{card_id}").json_into(Card)
+ client.get("/boards/#{self.id}/cards/#{card_id}").json_into(Card)
end
# Return all the cards on this board.
34 lib/trello/card.rb
View
@@ -53,7 +53,7 @@ def update_fields(fields)
many :checklists, :filter => :all
def check_item_states
- states = Client.get("/cards/#{self.id}/checkItemStates").json_into(CheckItemState)
+ states = client.get("/cards/#{self.id}/checkItemStates").json_into(CheckItemState)
MultiAssociation.new(self, states).proxy
end
@@ -64,7 +64,7 @@ def check_item_states
# Returns a list of members who are assigned to this card.
def members
members = member_ids.map do |member_id|
- Client.get("/members/#{member_id}").json_into(Member)
+ client.get("/members/#{member_id}").json_into(Member)
end
MultiAssociation.new(self, members).proxy
end
@@ -74,7 +74,7 @@ def save
# If we have an id, just update our fields.
return update! if id
- Client.post("/cards", {
+ client.post("/cards", {
:name => name,
:desc => description,
:idList => list_id
@@ -91,7 +91,7 @@ def update!
payload = Hash[changes.map { |key, values| [key.to_sym, values[1]] }]
@changed_attributes.clear
- Client.put("/cards/#{id}", payload)
+ client.put("/cards/#{id}", payload)
end
# Check if the card is not active anymore.
@@ -115,12 +115,12 @@ def valid?
# Add a comment with the supplied text.
def add_comment(text)
- Client.post("/cards/#{id}/actions/comments", :text => text)
+ client.post("/cards/#{id}/actions/comments", :text => text)
end
# Add a checklist to this card
def add_checklist(checklist)
- Client.post("/cards/#{id}/checklists", {
+ client.post("/cards/#{id}/checklists", {
:value => checklist.id
})
end
@@ -128,7 +128,7 @@ def add_checklist(checklist)
# Move this card to the given list
def move_to_list(list)
unless list_id == list.id
- Client.put("/cards/#{id}/idList", {
+ client.put("/cards/#{id}/idList", {
:value => list.id
})
end
@@ -139,25 +139,25 @@ def move_to_board(new_board, new_list = nil)
unless board_id == new_board.id
payload = { :value => new_board.id }
payload[:idList] = new_list.id if new_list
- Client.put("/cards/#{id}/idBoard", payload)
+ client.put("/cards/#{id}/idBoard", payload)
end
end
# Add a member to this card
def add_member(member)
- Client.post("/cards/#{id}/members", {
+ client.post("/cards/#{id}/members", {
:value => member.id
})
end
# Remove a member from this card
def remove_member(member)
- Client.delete("/cards/#{id}/members/#{member.id}")
+ client.delete("/cards/#{id}/members/#{member.id}")
end
# Retrieve a list of labels
def labels
- labels = Client.get("/cards/#{id}/labels").json_into(Label)
+ labels = client.get("/cards/#{id}/labels").json_into(Label)
MultiAssociation.new(self, labels).proxy
end
@@ -167,7 +167,7 @@ def add_label(colour)
errors.add(:label, "colour '#{colour}' does not exist")
return Trello.logger.warn "The label colour '#{colour}' does not exist."
end
- Client.post("/cards/#{id}/labels", { :value => colour })
+ client.post("/cards/#{id}/labels", { :value => colour })
end
# Remove a label
@@ -176,18 +176,18 @@ def remove_label(colour)
errors.add(:label, "colour '#{colour}' does not exist")
return Trello.logger.warn "The label colour '#{colour}' does not exist." unless %w{green yellow orange red purple blue}.include? colour
end
- Client.delete("/cards/#{id}/labels/#{colour}")
+ client.delete("/cards/#{id}/labels/#{colour}")
end
# Add an attachment to this card
def add_attachment(attachment, name='')
if attachment.is_a? File
- Client.post("/cards/#{id}/attachments", {
+ client.post("/cards/#{id}/attachments", {
:file => attachment,
:name => name
})
else
- Client.post("/cards/#{id}/attachments", {
+ client.post("/cards/#{id}/attachments", {
:url => attachment,
:name => name
})
@@ -196,13 +196,13 @@ def add_attachment(attachment, name='')
# Retrieve a list of attachments
def attachments
- attachments = Client.get("/cards/#{id}/attachments").json_into(Attachment)
+ attachments = client.get("/cards/#{id}/attachments").json_into(Attachment)
MultiAssociation.new(self, attachments).proxy
end
# Remove an attachment from this card
def remove_attachment(attachment)
- Client.delete("/cards/#{id}/attachments/#{attachment.id}")
+ client.delete("/cards/#{id}/attachments/#{attachment.id}")
end
# :nodoc:
6 lib/trello/checklist.rb
View
@@ -43,14 +43,14 @@ def closed?
def save
return update! if id
- Client.post("/checklists", {
+ client.post("/checklists", {
:name => name,
:idBoard => board_id
}).json_into(self)
end
def update!
- Client.put("/checklists/#{id}", { :name => name }).json_into(self)
+ client.put("/checklists/#{id}", { :name => name }).json_into(self)
end
# Return a list of items on the checklist.
@@ -76,7 +76,7 @@ def members
# Add an item to the checklist
def add_item(name)
- Client.post("/checklists/#{id}/checkItems", { :name => name })
+ client.post("/checklists/#{id}/checkItems", { :name => name })
end
end
end
79 lib/trello/client.rb
View
@@ -2,48 +2,65 @@
module Trello
class Client
- extend Authorization
+ include Authorization
- class << self
- def get(path, params = {})
- uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
- uri.query_values = params unless params.empty?
- invoke_verb(:get, uri)
- end
+ def get(path, params = {})
+ uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
+ uri.query_values = params unless params.empty?
+ invoke_verb(:get, uri)
+ end
- def post(path, body = {})
- uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
- invoke_verb(:post, uri, body)
- end
+ def post(path, body = {})
+ uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
+ invoke_verb(:post, uri, body)
+ end
- def put(path, body = {})
- uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
- invoke_verb(:put, uri, body)
- end
+ def put(path, body = {})
+ uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
+ invoke_verb(:put, uri, body)
+ end
+
+ def delete(path)
+ uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
+ invoke_verb(:delete, uri)
+ end
- def delete(path)
- uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
- invoke_verb(:delete, uri)
+ def invoke_verb(name, uri, body = nil)
+ request = Request.new name, uri, {}, body
+ response = TInternet.execute auth_policy.authorize(request)
+
+ return '' unless response
+
+ if response.code.to_i == 401 && response.body =~ /expired token/
+ Trello.logger.error("[401 #{name.to_s.upcase} #{uri}]: Your access token has expired.")
+ raise InvalidAccessToken, response.body
end
- def invoke_verb(name, uri, body = nil)
- request = Request.new name, uri, {}, body
- response = TInternet.execute AuthPolicy.authorize(request)
+ unless [200, 201].include? response.code
+ Trello.logger.error("[#{response.code} #{name.to_s.upcase} #{uri}]: #{response.body}")
+ raise Error, response.body
+ end
- return '' unless response
+ response.body
+ end
- if response.code.to_i == 401 && response.body =~ /expired token/
- Trello.logger.error("[401 #{name.to_s.upcase} #{uri}]: Your access token has expired.")
- raise InvalidAccessToken, response.body
- end
+ def configuration
+ @configuration ||= Configuration.new
+ end
- unless [200, 201].include? response.code
- Trello.logger.error("[#{response.code} #{name.to_s.upcase} #{uri}]: #{response.body}")
- raise Error, response.body
- end
+ def auth_policy
+ @auth_policy ||= auth_policy_class.new(configuration.credentials)
+ end
- response.body
+ def auth_policy_class
+ if configuration.oauth?
+ OAuthPolicy
+ elsif configuration.basic?
+ BasicAuthPolicy
+ else
+ AuthPolicy
end
end
+
end
end
51 lib/trello/configuration.rb
View
@@ -0,0 +1,51 @@
+module Trello
+ class Configuration
+ attr_accessor :developer_public_key, :member_token
+ attr_accessor :consumer_key, :consumer_secret, :oauth_token, :oauth_token_secret
+ attr_accessor :callback, :return_url
+
+ def initialize(attrs = {})
+ attrs.each { |key, value| instance_variable_set("@#{key}", value) }
+ end
+
+ def credentials
+ case
+ when oauth?
+ oauth_credentials
+ when basic?
+ basic_credentials
+ else
+ {}
+ end
+ end
+
+ def oauth?
+ consumer_key && consumer_secret
+ end
+
+ def basic?
+ developer_public_key && member_token
+ end
+
+ private
+
+ def oauth_credentials
+ {
+ :consumer_key => consumer_key,
+ :consumer_secret => consumer_secret,
+ :oauth_token => oauth_token,
+ :oauth_token_secret => oauth_token_secret,
+ :return_url => return_url,
+ :callback => callback,
+ }.delete_if { |key, value| value.nil? }
+ end
+
+ def basic_credentials
+ {
+ :developer_public_key => developer_public_key,
+ :member_token => member_token
+ }
+ end
+
+ end
+end
2  lib/trello/has_actions.rb
View
@@ -2,7 +2,7 @@ module Trello
module HasActions
# Returns a list of the actions associated with this object.
def actions(options = {})
- actions = Client.get("#{request_prefix}/actions", { :filter => :all }.merge(options)).json_into(Action)
+ actions = client.get("#{request_prefix}/actions", { :filter => :all }.merge(options)).json_into(Action)
MultiAssociation.new(self, actions).proxy
end
end
4 lib/trello/list.rb
View
@@ -35,7 +35,7 @@ def update_fields(fields)
def save
return update! if id
- Client.post("/lists", {
+ client.post("/lists", {
:name => name,
:closed => closed || false,
:idBoard => board_id
@@ -43,7 +43,7 @@ def save
end
def update!
- Client.put("/lists/#{id}", {
+ client.put("/lists/#{id}", {
:name => name,
:closed => closed
})
4 lib/trello/member.rb
View
@@ -32,7 +32,7 @@ def update_fields(fields)
end
# Retrieve a URL to the avatar.
- #
+ #
# Valid values for options are:
# :large (170x170)
# :small (30x30)
@@ -79,7 +79,7 @@ def save
end
def update!
- Client.put(request_prefix, {
+ client.put(request_prefix, {
:fullName => full_name,
:bio => bio
}).json_into(self)
12 lib/trello/notification.rb
View
@@ -26,23 +26,23 @@ def update_fields(fields)
one :member_creator, :via => Member, :using => :member_creator_id
def board
- Client.get("/notifications/#{id}/board").json_into(Board)
+ client.get("/notifications/#{id}/board").json_into(Board)
end
def list
- Client.get("/notifications/#{id}/list").json_into(List)
+ client.get("/notifications/#{id}/list").json_into(List)
end
def card
- Client.get("/notifications/#{id}/card").json_into(Card)
+ client.get("/notifications/#{id}/card").json_into(Card)
end
def member
- Client.get("/notifications/#{id}/member").json_into(Member)
+ client.get("/notifications/#{id}/member").json_into(Member)
end
def organization
- Client.get("/notifications/#{id}/organization").json_into(Organization)
+ client.get("/notifications/#{id}/organization").json_into(Organization)
end
end
-end
+end
4 lib/trello/organization.rb
View
@@ -29,13 +29,13 @@ def update_fields(fields)
# Returns a list of boards under this organization.
def boards
- boards = Client.get("/organizations/#{id}/boards/all").json_into(Board)
+ boards = client.get("/organizations/#{id}/boards/all").json_into(Board)
MultiAssociation.new(self, boards).proxy
end
# Returns an array of members associated with the organization.
def members
- members = Client.get("/organizations/#{id}/members/all").json_into(Member)
+ members = client.get("/organizations/#{id}/members/all").json_into(Member)
MultiAssociation.new(self, members).proxy
end
12 spec/action_spec.rb
View
@@ -5,7 +5,7 @@ module Trello
include Helpers
before(:each) do
- Client.stub(:get).with("/actions/4ee2482134a81a757a08af47").
+ Trello.client.stub(:get).with("/actions/4ee2482134a81a757a08af47").
and_return JSON.generate(actions_details.first)
@action = Action.find('4ee2482134a81a757a08af47')
@@ -35,7 +35,7 @@ module Trello
context "boards" do
it "has a board" do
- Client.stub(:get).with("/actions/4ee2482134a81a757a08af47/board").
+ Trello.client.stub(:get).with("/actions/4ee2482134a81a757a08af47/board").
and_return JSON.generate(boards_details.first)
@action.board.should_not be_nil
@@ -44,16 +44,16 @@ module Trello
context "card" do
it "has a card" do
- Client.stub(:get).with("/actions/4ee2482134a81a757a08af47/card").
+ Trello.client.stub(:get).with("/actions/4ee2482134a81a757a08af47/card").
and_return JSON.generate(cards_details.first)
-
+
@action.card.should_not be_nil
end
end
context "list" do
it "has a list of lists" do
- Client.stub(:get).with("/actions/4ee2482134a81a757a08af47/list").
+ Trello.client.stub(:get).with("/actions/4ee2482134a81a757a08af47/list").
and_return JSON.generate(lists_details.first)
@action.list.should_not be_nil
@@ -62,7 +62,7 @@ module Trello
context "member creator" do
it "knows its member creator" do
- Client.stub(:get).with("/members/abcdef123456789123456789").and_return user_payload
+ Trello.client.stub(:get).with("/members/abcdef123456789123456789").and_return user_payload
@action.member_creator.should_not be_nil
end
1  spec/basic_auth_policy_spec.rb
View
@@ -1,5 +1,6 @@
require "spec_helper"
+include Trello
include Trello::Authorization
describe BasicAuthPolicy do
32 spec/board_spec.rb
View
@@ -5,7 +5,7 @@ module Trello
include Helpers
before(:each) do
- Client.stub(:get).with("/boards/abcdef123456789123456789").
+ Trello.client.stub(:get).with("/boards/abcdef123456789123456789").
and_return JSON.generate(boards_details.first)
@board = Board.find('abcdef123456789123456789')
@@ -13,7 +13,7 @@ module Trello
it "gets all boards" do
Member.stub_chain(:find, :username).and_return "testuser"
- Client.stub(:get).with("/members/testuser/boards").and_return boards_payload
+ Trello.client.stub(:get).with("/members/testuser/boards").and_return boards_payload
expected = Board.new(boards_details.first)
Board.all.first.should eq(expected)
@@ -43,7 +43,7 @@ module Trello
context "actions" do
it "has a list of actions" do
- Client.stub(:get).with("/boards/abcdef123456789123456789/actions", {:filter => :all}).
+ Trello.client.stub(:get).with("/boards/abcdef123456789123456789/actions", {:filter => :all}).
and_return actions_payload
@board.actions.count.should be > 0
@@ -52,7 +52,7 @@ module Trello
context "cards" do
it "gets its list of cards" do
- Client.stub(:get).with("/boards/abcdef123456789123456789/cards", { :filter => :open }).
+ Trello.client.stub(:get).with("/boards/abcdef123456789123456789/cards", { :filter => :open }).
and_return cards_payload
@board.cards.count.should be > 0
@@ -61,7 +61,7 @@ module Trello
context "find_card" do
it "gets a card" do
- Client.stub(:get).with("/boards/abcdef123456789123456789/cards/1").
+ Trello.client.stub(:get).with("/boards/abcdef123456789123456789/cards/1").
and_return card_payload
@board.find_card(1).should be_a(Card)
end
@@ -69,7 +69,7 @@ module Trello
context "lists" do
it "has a list of lists" do
- Client.stub(:get).with("/boards/abcdef123456789123456789/lists", hash_including(:filter => :open)).
+ Trello.client.stub(:get).with("/boards/abcdef123456789123456789/lists", hash_including(:filter => :open)).
and_return lists_payload
@board.has_lists?.should be true
@@ -78,7 +78,7 @@ module Trello
context "members" do
it "has a list of members" do
- Client.stub(:get).with("/boards/abcdef123456789123456789/members", hash_including(:filter => :all)).
+ Trello.client.stub(:get).with("/boards/abcdef123456789123456789/members", hash_including(:filter => :all)).
and_return JSON.generate([user_details])
@board.members.count.should be > 0
@@ -87,7 +87,7 @@ module Trello
context "organization" do
it "belongs to an organization" do
- Client.stub(:get).with("/organizations/abcdef123456789123456789").
+ Trello.client.stub(:get).with("/organizations/abcdef123456789123456789").
and_return JSON.generate(orgs_details.first)
@board.organization.should_not be_nil
@@ -135,7 +135,7 @@ module Trello
end
it "cannot currently save a new instance" do
- Client.should_not_receive :put
+ Trello.client.should_not_receive :put
the_new_board = Board.new
lambda{the_new_board.save}.should raise_error
@@ -144,7 +144,7 @@ module Trello
it "puts all fields except id" do
expected_fields = %w{name description closed}.map{|s| s.to_sym}
- Client.should_receive(:put) do |anything, body|
+ Trello.client.should_receive(:put) do |anything, body|
body.keys.should =~ expected_fields
any_board_json
end
@@ -154,7 +154,7 @@ module Trello
end
it "mutates the current instance" do
- Client.stub(:put).and_return any_board_json
+ Trello.client.stub(:put).and_return any_board_json
board = Board.new 'id' => "xxx"
@@ -166,7 +166,7 @@ module Trello
it "uses the correct resource" do
expected_resource_id = "xxx_board_id_xxx"
- Client.should_receive(:put) do |path, anything|
+ Trello.client.should_receive(:put) do |path, anything|
path.should =~ /#{expected_resource_id}\/$/
any_board_json
end
@@ -192,7 +192,7 @@ module Trello
board.description = "new description"
board.closed = true
- Client.should_receive(:put).with("/boards/#{board.id}/", {
+ Trello.client.should_receive(:put).with("/boards/#{board.id}/", {
:name => "new name",
:description => "new description",
:closed => true
@@ -212,19 +212,19 @@ module Trello
expected_attributes = { :name => "Any new board name", :description => "Any new board desription" }
sent_attributes = { :name => expected_attributes[:name], :desc => expected_attributes[:description] }
- Client.should_receive(:post).with("/boards", sent_attributes).and_return any_board_json
+ Trello.client.should_receive(:post).with("/boards", sent_attributes).and_return any_board_json
Board.create expected_attributes
end
it "posts to the boards collection" do
- Client.should_receive(:post).with("/boards", anything).and_return any_board_json
+ Trello.client.should_receive(:post).with("/boards", anything).and_return any_board_json
Board.create :xxx => ""
end
it "returns a board" do
- Client.stub(:post).with("/boards", anything).and_return any_board_json
+ Trello.client.stub(:post).with("/boards", anything).and_return any_board_json
the_new_board = Board.create :xxx => ""
the_new_board.should be_a Board
56 spec/card_spec.rb
View
@@ -7,7 +7,7 @@ module Trello
let(:card) { Card.find('abcdef123456789123456789') }
before(:each) do
- Client.stub(:get).with("/cards/abcdef123456789123456789").
+ Trello.client.stub(:get).with("/cards/abcdef123456789123456789").
and_return JSON.generate(cards_details.first)
end
@@ -37,7 +37,7 @@ module Trello
expected_payload = {:name => "Test Card", :desc => nil, :idList => "abcdef123456789123456789"}
- Client.should_receive(:post).with("/cards", expected_payload).and_return result
+ Trello.client.should_receive(:post).with("/cards", expected_payload).and_return result
card = Card.create(cards_details.first.merge(payload.merge(:list_id => lists_details.first['id'])))
@@ -53,7 +53,7 @@ module Trello
:name => expected_new_name,
}
- Client.should_receive(:put).once.with("/cards/abcdef123456789123456789", payload)
+ Trello.client.should_receive(:put).once.with("/cards/abcdef123456789123456789", payload)
card.name = expected_new_name
card.save
@@ -88,40 +88,40 @@ module Trello
context "actions" do
it "asks for all actions by default" do
- Client.stub(:get).with("/cards/abcdef123456789123456789/actions", { :filter => :all }).and_return actions_payload
+ Trello.client.stub(:get).with("/cards/abcdef123456789123456789/actions", { :filter => :all }).and_return actions_payload
card.actions.count.should be > 0
end
it "allows overriding the filter" do
- Client.stub(:get).with("/cards/abcdef123456789123456789/actions", { :filter => :updateCard }).and_return actions_payload
+ Trello.client.stub(:get).with("/cards/abcdef123456789123456789/actions", { :filter => :updateCard }).and_return actions_payload
card.actions(:filter => :updateCard).count.should be > 0
end
end
context "boards" do
it "has a board" do
- Client.stub(:get).with("/boards/abcdef123456789123456789").and_return JSON.generate(boards_details.first)
+ Trello.client.stub(:get).with("/boards/abcdef123456789123456789").and_return JSON.generate(boards_details.first)
card.board.should_not be_nil
end
end
context "checklists" do
it "has a list of checklists" do
- Client.stub(:get).with("/cards/abcdef123456789123456789/checklists", { :filter => :all }).and_return checklists_payload
+ Trello.client.stub(:get).with("/cards/abcdef123456789123456789/checklists", { :filter => :all }).and_return checklists_payload
card.checklists.count.should be > 0
end
end
context "list" do
it 'has a list' do
- Client.stub(:get).with("/lists/abcdef123456789123456789").and_return JSON.generate(lists_details.first)
+ Trello.client.stub(:get).with("/lists/abcdef123456789123456789").and_return JSON.generate(lists_details.first)
card.list.should_not be_nil
end
it 'can be moved to another list' do
other_list = stub(:id => '987654321987654321fedcba')
payload = {:value => other_list.id}
- Client.should_receive(:put).with("/cards/abcdef123456789123456789/idList", payload)
+ Trello.client.should_receive(:put).with("/cards/abcdef123456789123456789/idList", payload)
card.move_to_list(other_list)
end
@@ -135,7 +135,7 @@ module Trello
it 'can be moved to another board' do
other_board = stub(:id => '987654321987654321fedcba')
payload = {:value => other_board.id}
- Client.should_receive(:put).with("/cards/abcdef123456789123456789/idBoard", payload)
+ Trello.client.should_receive(:put).with("/cards/abcdef123456789123456789/idBoard", payload)
card.move_to_board(other_board)
end
@@ -143,7 +143,7 @@ module Trello
other_board = stub(:id => '987654321987654321fedcba')
other_list = stub(:id => '987654321987654321aalist')
payload = {:value => other_board.id, :idList => other_list.id}
- Client.should_receive(:put).with("/cards/abcdef123456789123456789/idBoard", payload)
+ Trello.client.should_receive(:put).with("/cards/abcdef123456789123456789/idBoard", payload)
card.move_to_board(other_board, other_list)
end
@@ -156,8 +156,8 @@ module Trello
context "members" do
it "has a list of members" do
- Client.stub(:get).with("/boards/abcdef123456789123456789").and_return JSON.generate(boards_details.first)
- Client.stub(:get).with("/members/abcdef123456789123456789").and_return user_payload
+ Trello.client.stub(:get).with("/boards/abcdef123456789123456789").and_return JSON.generate(boards_details.first)
+ Trello.client.stub(:get).with("/members/abcdef123456789123456789").and_return user_payload
card.board.should_not be_nil
card.members.should_not be_nil
@@ -168,20 +168,20 @@ module Trello
payload = {
:value => new_member.id
}
- Client.should_receive(:post).with("/cards/abcdef123456789123456789/members", payload)
+ Trello.client.should_receive(:post).with("/cards/abcdef123456789123456789/members", payload)
card.add_member(new_member)
end
it "allows a member to be removed from a card" do
existing_member = stub(:id => '4ee7df3ce582acdec80000b2')
- Client.should_receive(:delete).with("/cards/abcdef123456789123456789/members/#{existing_member.id}")
+ Trello.client.should_receive(:delete).with("/cards/abcdef123456789123456789/members/#{existing_member.id}")
card.remove_member(existing_member)
end
end
context "comments" do
it "posts a comment" do
- Client.should_receive(:post).
+ Trello.client.should_receive(:post).
with("/cards/abcdef123456789123456789/actions/comments", { :text => 'testing' }).
and_return JSON.generate(boards_details.first)
@@ -191,7 +191,7 @@ module Trello
context "labels" do
it "can retrieve labels" do
- Client.stub(:get).with("/cards/abcdef123456789123456789/labels").
+ Trello.client.stub(:get).with("/cards/abcdef123456789123456789/labels").
and_return label_payload
labels = card.labels
labels.size.should == 2
@@ -204,28 +204,28 @@ module Trello
end
it "can add a label" do
- Client.stub(:post).with("/cards/abcdef123456789123456789/labels", { :value => 'green' }).
+ Trello.client.stub(:post).with("/cards/abcdef123456789123456789/labels", { :value => 'green' }).
and_return "not important"
card.add_label('green')
card.errors.should be_empty
end
it "can remove a label" do
- Client.stub(:delete).with("/cards/abcdef123456789123456789/labels/green").
+ Trello.client.stub(:delete).with("/cards/abcdef123456789123456789/labels/green").
and_return "not important"
card.remove_label('green')
card.errors.should be_empty
end
it "throws an error when trying to add a label with an unknown colour" do
- Client.stub(:post).with("/cards/abcdef123456789123456789/labels", { :value => 'green' }).
+ Trello.client.stub(:post).with("/cards/abcdef123456789123456789/labels", { :value => 'green' }).
and_return "not important"
card.add_label('mauve')
card.errors.full_messages.to_sentence.should == "Label colour 'mauve' does not exist"
end
it "throws an error when trying to remove a label with an unknown colour" do
- Client.stub(:delete).with("/cards/abcdef123456789123456789/labels/mauve").
+ Trello.client.stub(:delete).with("/cards/abcdef123456789123456789/labels/mauve").
and_return "not important"
card.remove_label('mauve')
card.errors.full_messages.to_sentence.should == "Label colour 'mauve' does not exist"
@@ -235,8 +235,8 @@ module Trello
context "attachments" do
it "can add an attachment" do
f = File.new('spec/list_spec.rb', 'r')
- Client.stub(:get).with("/cards/abcdef123456789123456789/attachments").and_return attachments_payload
- Client.stub(:post).with("/cards/abcdef123456789123456789/attachments",
+ Trello.client.stub(:get).with("/cards/abcdef123456789123456789/attachments").and_return attachments_payload
+ Trello.client.stub(:post).with("/cards/abcdef123456789123456789/attachments",
{ :file => f, :name => '' }).
and_return "not important"
@@ -246,17 +246,17 @@ module Trello
end
it "can list the existing attachments" do
- Client.stub(:get).with("/boards/abcdef123456789123456789").and_return JSON.generate(boards_details.first)
- Client.stub(:get).with("/cards/abcdef123456789123456789/attachments").and_return attachments_payload
+ Trello.client.stub(:get).with("/boards/abcdef123456789123456789").and_return JSON.generate(boards_details.first)
+ Trello.client.stub(:get).with("/cards/abcdef123456789123456789/attachments").and_return attachments_payload
card.board.should_not be_nil
card.attachments.should_not be_nil
end
it "can remove an attachment" do
- Client.stub(:delete).with("/cards/abcdef123456789123456789/attachments/abcdef123456789123456789").
+ Trello.client.stub(:delete).with("/cards/abcdef123456789123456789/attachments/abcdef123456789123456789").
and_return "not important"
- Client.stub(:get).with("/cards/abcdef123456789123456789/attachments").and_return attachments_payload
+ Trello.client.stub(:get).with("/cards/abcdef123456789123456789/attachments").and_return attachments_payload
card.remove_attachment(card.attachments.first)
card.errors.should be_empty
@@ -282,7 +282,7 @@ module Trello
:closed => true,
}
- Client.should_receive(:put).once.with("/cards/abcdef123456789123456789", payload)
+ Trello.client.should_receive(:put).once.with("/cards/abcdef123456789123456789", payload)
card.close!
end
6 spec/checklist_spec.rb
View
@@ -7,7 +7,7 @@ module Trello
let(:checklist) { Checklist.find('abcdef123456789123456789') }
before(:each) do
- Client.stub(:get).with("/checklists/abcdef123456789123456789").
+ Trello.client.stub(:get).with("/checklists/abcdef123456789123456789").
and_return JSON.generate(checklists_details.first)
end
@@ -22,7 +22,7 @@ module Trello
expected_payload = {:name => "Test Checklist", :idBoard => "abcdef123456789123456789"}
- Client.should_receive(:post).with("/checklists", expected_payload).and_return result
+ Trello.client.should_receive(:post).with("/checklists", expected_payload).and_return result
checklist = Checklist.create(checklists_details.first.merge(payload.merge(:board_id => boards_details.first['id'])))
@@ -39,7 +39,7 @@ module Trello
}
result = JSON.generate(checklists_details.first)
- Client.should_receive(:put).once.with("/checklists/abcdef123456789123456789", payload).and_return result
+ Trello.client.should_receive(:put).once.with("/checklists/abcdef123456789123456789", payload).and_return result
checklist.name = expected_new_name
checklist.save
41 spec/client_spec.rb
View
@@ -9,19 +9,22 @@
:code => 200,
:body => "A fake response body"
}
-
+ let(:client) { Client.new }
+ let(:auth_policy) { stub }
+
before do
TInternet.stub(:execute).and_return fake_ok_response
- Authorization::AuthPolicy.stub(:authorize) do |request|
+ Authorization::AuthPolicy.stub(:new).and_return(auth_policy)
+ auth_policy.stub(:authorize) do |request|
request
end
end
it "authorizes before it queries the internet" do
- AuthPolicy.should_receive(:authorize).once.ordered
+ auth_policy.should_receive(:authorize).once.ordered
TInternet.should_receive(:execute).once.ordered
- Client.get "/xxx"
+ client.get "/xxx"
end
it "queries the internet with expanded earl and query parameters" do
@@ -30,7 +33,7 @@
TInternet.should_receive(:execute).once.with expected_request
- Client.get "/xxx", :a => "1", :b => "2"
+ client.get "/xxx", :a => "1", :b => "2"
end
it "encodes parameters" do
@@ -39,42 +42,42 @@
TInternet.should_receive(:execute).once.with expected_request
- Client.get "/xxx", :name => "Jazz Kang"
+ client.get "/xxx", :name => "Jazz Kang"
end
it "raises an error when response has non-200 status" do
expected_error_message = "An error response"
- response_with_non_200_status = stub "A fake OK response",
+ response_with_non_200_status = stub "A fake OK response",
:code => 404,
:body => expected_error_message
TInternet.stub(:execute).and_return response_with_non_200_status
- lambda{Client.get "/xxx"}.should raise_error expected_error_message
+ lambda{client.get "/xxx"}.should raise_error expected_error_message
end
it "uses version 1 of the API" do
TInternet.should_receive(:execute).once do |request|
request.uri.to_s.should =~ /1\//
fake_ok_response
- end
+ end
- Client.get "/"
- end
+ client.get "/"
+ end
it "omits the \"?\" when no parameters" do
TInternet.should_receive(:execute).once do |request|
request.uri.to_s.should_not =~ /\?$/
fake_ok_response
- end
+ end
- Client.get "/xxx"
+ client.get "/xxx"
end
it "supports post" do
TInternet.should_receive(:execute).once.and_return fake_ok_response
- Client.post "/xxx", { :phil => "T' north" }
+ client.post "/xxx", { :phil => "T' north" }
end
it "supplies the body for a post" do
@@ -85,7 +88,7 @@
fake_ok_response
end
- Client.post "/xxx", expected_body
+ client.post "/xxx", expected_body
end
it "supplies the path for a post" do
@@ -96,7 +99,7 @@
fake_ok_response
end
- Client.post "/xxx", {}
+ client.post "/xxx", {}
end
it "supports put" do
@@ -104,7 +107,7 @@
TInternet.should_receive(:execute).once.and_return fake_ok_response
- Client.put "/xxx", { :phil => "T' north" }
+ client.put "/xxx", { :phil => "T' north" }
end
it "supplies the body for a put" do
@@ -115,7 +118,7 @@
fake_ok_response
end
- Client.put "/xxx", expected_body
+ client.put "/xxx", expected_body
end
it "supplies the path for a put" do
@@ -126,6 +129,6 @@
fake_ok_response
end
- Client.put "/xxx", {}
+ client.put "/xxx", {}
end
end
114 spec/configuration_spec.rb
View
@@ -0,0 +1,114 @@
+require "spec_helper"
+
+describe Trello::Configuration do
+ let(:configuration) { Trello::Configuration.new }
+
+ it "has a consumer_key attribute" do
+ configuration.consumer_key = 'consumer_key'
+ configuration.consumer_key.should eq('consumer_key')
+ end
+
+ it "has a consumer_secret attribute" do
+ configuration.consumer_secret = 'consumer_secret'
+ configuration.consumer_secret.should eq('consumer_secret')
+ end
+
+ it "has a oauth_token attribute" do
+ configuration.oauth_token = 'oauth_token'
+ configuration.oauth_token.should eq('oauth_token')
+ end
+
+ it "has a oauth_token_secret attribute" do
+ configuration.oauth_token_secret = 'oauth_token_secret'
+ configuration.oauth_token_secret.should eq('oauth_token_secret')
+ end
+
+ it "has a developer public key attribute" do
+ configuration.developer_public_key = 'developer_public_key'
+ configuration.developer_public_key.should eq('developer_public_key')
+ end
+
+ it "has a member token attribute" do
+ configuration.member_token = 'member_token'
+ configuration.member_token.should eq('member_token')
+ end
+
+ it "has a callback (for oauth)" do
+ callback = lambda { 'foobar' }
+ configuration.callback = callback
+ configuration.callback.call.should eq('foobar')
+ end
+
+ it "has a return_url" do
+ configuration.return_url = "http://www.example.com/callback"
+ configuration.return_url.should eq("http://www.example.com/callback")
+ end
+
+ describe "initialize" do
+ it "sets key attributes provided as a hash" do
+ configuration = Trello::Configuration.new(
+ :consumer_key => 'consumer_key',
+ :consumer_secret => 'consumer_secret',
+ :oauth_token => 'oauth_token',
+ :oauth_token_secret => 'oauth_token_secret'
+ )
+ configuration.consumer_key.should eq('consumer_key')
+ configuration.consumer_secret.should eq('consumer_secret')
+ configuration.oauth_token.should eq('oauth_token')
+ configuration.oauth_token_secret.should eq('oauth_token_secret')
+ end
+ end
+
+ describe "#credentials" do
+ let(:configuration) { Trello::Configuration.new(attributes) }
+
+ it "returns an empty if no attributes specified" do
+ Trello::Configuration.new({}).credentials.should eq({})
+ end
+
+ it "returns an empty if attributes incomplete" do
+ Trello::Configuration.new(:consumer_key => 'consumer_key').credentials.should eq({})
+ end
+
+ it 'returns a hash of oauth attributes' do
+ configuration = Trello::Configuration.new(
+ :consumer_key => 'consumer_key',
+ :consumer_secret => 'consumer_secret',
+ :oauth_token => 'oauth_token',
+ :oauth_token_secret => 'oauth_token_secret'
+ )
+ configuration.credentials.should eq(
+ :consumer_key => 'consumer_key',
+ :consumer_secret => 'consumer_secret',
+ :oauth_token => 'oauth_token',
+ :oauth_token_secret => 'oauth_token_secret'
+ )
+ end
+
+ it 'includes callback and return url if given' do
+ configuration = Trello::Configuration.new(
+ :consumer_key => 'consumer_key',
+ :consumer_secret => 'consumer_secret',
+ :return_url => 'http://example.com',
+ :callback => 'callback'
+ )
+ configuration.credentials.should eq(
+ :consumer_key => 'consumer_key',
+ :consumer_secret => 'consumer_secret',
+ :return_url => 'http://example.com',
+ :callback => 'callback'
+ )
+ end
+
+ it "returns a hash of basic auth policy attributes" do
+ configuration = Trello::Configuration.new(
+ :developer_public_key => 'developer_public_key',
+ :member_token => 'member_token'
+ )
+ configuration.credentials.should eq(
+ :developer_public_key => 'developer_public_key',
+ :member_token => 'member_token'
+ )
+ end
+ end
+end
2  spec/integration/how_to_authorize_spec.rb
View
@@ -45,7 +45,7 @@
it "[!] actually does not enforce signature at all, only the keys are required" do
OAuthPolicy.consumer_credential = OAuthCredential.new @developer_public_key, nil
OAuthPolicy.token = OAuthCredential.new @access_token_key, nil
-
+
pending "I would expect this to fail because I have signed with nil secrets" do
lambda{Client.get("/boards/#{@welcome_board}/")}.should raise_error
end
12 spec/list_spec.rb
View
@@ -5,8 +5,8 @@ module Trello
include Helpers
before(:each) do
- Client.stub(:get).with("/lists/abcdef123456789123456789").and_return JSON.generate(lists_details.first)
- Client.stub(:get).with("/boards/abcdef123456789123456789").and_return JSON.generate(boards_details.first)
+ Trello.client.stub(:get).with("/lists/abcdef123456789123456789").and_return JSON.generate(lists_details.first)
+ Trello.client.stub(:get).with("/boards/abcdef123456789123456789").and_return JSON.generate(boards_details.first)
@list = List.find("abcdef123456789123456789")
end
@@ -20,7 +20,7 @@ module Trello
:closed => false
}
- Client.should_receive(:put).once.with("/lists/abcdef123456789123456789", payload)
+ Trello.client.should_receive(:put).once.with("/lists/abcdef123456789123456789", payload)
@list.name = expected_new_name
@list.save
end
@@ -50,14 +50,14 @@ module Trello
context "actions" do
it "has a list of actions" do
- Client.stub(:get).with("/lists/abcdef123456789123456789/actions", { :filter => :all }).and_return actions_payload
+ Trello.client.stub(:get).with("/lists/abcdef123456789123456789/actions", { :filter => :all }).and_return actions_payload
@list.actions.count.should be > 0
end
end
context "cards" do
it "has a list of cards" do
- Client.stub(:get).with("/lists/abcdef123456789123456789/cards", { :filter => :open }).and_return cards_payload
+ Trello.client.stub(:get).with("/lists/abcdef123456789123456789/cards", { :filter => :open }).and_return cards_payload
@list.cards.count.should be > 0
end
end
@@ -77,7 +77,7 @@ module Trello
describe "#close!" do
it "updates the close attribute to true and saves the list" do
- Client.should_receive(:put).once.with("/lists/abcdef123456789123456789", {
+ Trello.client.should_receive(:put).once.with("/lists/abcdef123456789123456789", {
:name => @list.name,
:closed => true
})
12 spec/member_spec.rb
View
@@ -7,21 +7,21 @@ module Trello
include Helpers
before(:each) do
- Client.stub(:get).with("/members/abcdef123456789012345678").and_return user_payload
+ Trello.client.stub(:get).with("/members/abcdef123456789012345678").and_return user_payload
@member = Member.find('abcdef123456789012345678')
end
context "actions" do
it "retrieves a list of actions", :refactor => true do
- Client.stub(:get).with("/members/abcdef123456789012345678/actions", { :filter => :all }).and_return actions_payload
+ Trello.client.stub(:get).with("/members/abcdef123456789012345678/actions", { :filter => :all }).and_return actions_payload
@member.actions.count.should be > 0
end
end
context "boards" do
it "has a list of boards" do
- Client.stub(:get).with("/members/abcdef123456789012345678/boards", { :filter => :all }).and_return boards_payload
+ Trello.client.stub(:get).with("/members/abcdef123456789012345678/boards", { :filter => :all }).and_return boards_payload
boards = @member.boards
boards.count.should be > 0
end
@@ -29,7 +29,7 @@ module Trello
context "cards" do
it "has a list of cards" do
- Client.stub(:get).with("/members/abcdef123456789012345678/cards", { :filter => :open }).and_return cards_payload
+ Trello.client.stub(:get).with("/members/abcdef123456789012345678/cards", { :filter => :open }).and_return cards_payload
cards = @member.cards
cards.count.should be > 0
end
@@ -37,7 +37,7 @@ module Trello
context "organizations" do
it "has a list of organizations" do
- Client.stub(:get).with("/members/abcdef123456789012345678/organizations", { :filter => :all }).and_return orgs_payload
+ Trello.client.stub(:get).with("/members/abcdef123456789012345678/organizations", { :filter => :all }).and_return orgs_payload
orgs = @member.organizations
orgs.count.should be > 0
end
@@ -45,7 +45,7 @@ module Trello
context "notifications" do
it "has a list of notifications" do
- Client.stub(:get).with("/members/abcdef123456789012345678/notifications", {}).and_return "[" << notification_payload << "]"
+ Trello.client.stub(:get).with("/members/abcdef123456789012345678/notifications", {}).and_return "[" << notification_payload << "]"
@member.notifications.count.should be 1
end
end
20 spec/notification_spec.rb
View
@@ -5,55 +5,55 @@ module Trello
include Helpers
before(:each) do
- Client.stub(:get).with("/members/abcdef123456789012345678").and_return user_payload
+ Trello.client.stub(:get).with("/members/abcdef123456789012345678").and_return user_payload
member = Member.find("abcdef123456789012345678")
- Client.stub(:get).with("/members/abcdef123456789012345678/notifications", {}).and_return "[" << notification_payload << "]"
+ Trello.client.stub(:get).with("/members/abcdef123456789012345678/notifications", {}).and_return "[" << notification_payload << "]"
@notification = member.notifications.first
end
context "finding" do
it "can find a specific notification" do
- Client.stub(:get).with("/notifications/#{notification_details['id']}").and_return notification_payload
+ Trello.client.stub(:get).with("/notifications/#{notification_details['id']}").and_return notification_payload
Notification.find(notification_details['id']).should == @notification
end
end
context "boards" do
it "can retrieve the board" do
- Client.stub(:get).with("/notifications/#{notification_details['id']}/board").and_return JSON.generate(boards_details.first)
+ Trello.client.stub(:get).with("/notifications/#{notification_details['id']}/board").and_return JSON.generate(boards_details.first)
@notification.board.id.should == boards_details.first['id']
end
end
context "lists" do
it "can retrieve the list" do
- Client.stub(:get).with("/notifications/#{notification_details['id']}/list").and_return JSON.generate(lists_details.first)
+ Trello.client.stub(:get).with("/notifications/#{notification_details['id']}/list").and_return JSON.generate(lists_details.first)
@notification.list.id.should == lists_details.first['id']
end
end
context "cards" do
it "can retrieve the card" do
- Client.stub(:get).with("/notifications/#{notification_details['id']}/card").and_return JSON.generate(cards_details.first)
+ Trello.client.stub(:get).with("/notifications/#{notification_details['id']}/card").and_return JSON.generate(cards_details.first)
@notification.card.id.should == cards_details.first['id']
end
end
context "members" do
it "can retrieve the member" do
- Client.stub(:get).with("/notifications/#{notification_details['id']}/member").and_return user_payload
+ Trello.client.stub(:get).with("/notifications/#{notification_details['id']}/member").and_return user_payload
@notification.member.id.should == user_details['id']
end
it "can retrieve the member creator" do
- Client.stub(:get).with("/members/#{user_details['id']}").and_return user_payload
+ Trello.client.stub(:get).with("/members/#{user_details['id']}").and_return user_payload
@notification.member_creator.id.should == user_details['id']
end
end
context "organization" do
it "can retrieve the organization" do
- Client.stub(:get).with("/notifications/#{notification_details['id']}/organization").and_return JSON.generate(orgs_details.first)
+ Trello.client.stub(:get).with("/notifications/#{notification_details['id']}/organization").and_return JSON.generate(orgs_details.first)
@notification.organization.id.should == orgs_details.first['id']
end
end
@@ -80,4 +80,4 @@ module Trello
end
end
end
-end
+end
64 spec/oauth_policy_spec.rb
View
@@ -1,7 +1,7 @@
require "spec_helper"
-include Trello::Authorization
include Trello
+include Trello::Authorization
describe OAuthPolicy do
before do
@@ -9,19 +9,65 @@
OAuthPolicy.token = nil
end
+ describe "#consumer_credential" do
+ it "uses class setting if available" do
+ policy = OAuthPolicy.new
+ policy.consumer_credential.key.should eq('xxx')
+ policy.consumer_credential.secret.should eq('xxx')
+ end
+
+ it "is built from given consumer_key and consumer_secret" do
+ policy = OAuthPolicy.new(
+ :consumer_key => 'consumer_key',
+ :consumer_secret => 'consumer_secret'
+ )
+ policy.consumer_credential.key.should eq('consumer_key')
+ policy.consumer_credential.secret.should eq('consumer_secret')
+ end
+
+ it "is nil if none supplied to class" do
+ OAuthPolicy.consumer_credential = nil
+ policy = OAuthPolicy.new
+ policy.consumer_credential.should be_nil
+ end
+ end
+
+ describe "#token" do
+ it "uses class setting if available" do
+ OAuthPolicy.token = OAuthCredential.new "xxx", "xxx"
+ policy = OAuthPolicy.new
+ policy.token.key.should eq('xxx')
+ policy.token.secret.should eq('xxx')
+ end
+
+ it "is built from given oauth_token and oauth_token_secret" do
+ policy = OAuthPolicy.new(
+ :oauth_token => 'oauth_token',
+ :oauth_token_secret => 'oauth_token_secret'
+ )
+ policy.token.key.should eq('oauth_token')
+ policy.token.secret.should eq('oauth_token_secret')
+ end
+
+ it "is an empty token if no oauth credentials supplied" do
+ policy = OAuthPolicy.new
+ policy.token.should be_nil
+ end
+ end
+
context "2-legged" do
- it "adds an authorization header" do
+ it "adds an authorization header" do
uri = Addressable::URI.parse("https://xxx/")
request = Request.new :get, uri
- OAuthPolicy.token = OAuthCredential.new "token", nil
+ OAuthPolicy.token = OAuthCredential.new "token", nil
authorized_request = OAuthPolicy.authorize request
-
+
authorized_request.headers.keys.should include "Authorization"
end
-
+
it "preserves query parameters" do
uri = Addressable::URI.parse("https://xxx/?name=Riccardo")
request = Request.new :get, uri
@@ -32,12 +78,12 @@
OAuthPolicy.token = OAuthCredential.new "token", nil
authorized_request = OAuthPolicy.authorize request
-
+
the_query_parameters = Addressable::URI.parse(authorized_request.uri).query_values
the_query_parameters.should == {"name" => "Riccardo"}
end
- it "adds the correct signature as part of authorization header" do
+ it "adds the correct signature as part of authorization header" do
Clock.stub(:timestamp).and_return "1327048592"
Nonce.stub(:next).and_return "b94ff2bf7f0a5e87a326064ae1dbb18f"
@@ -47,7 +93,7 @@
request = Request.new :get, Addressable::URI.parse("http://xxx/")
authorized_request = OAuthPolicy.authorize request
-
+
authorized_request.headers["Authorization"].should =~ /oauth_signature="TVNk%2FCs03FHqutDUqn05%2FDkvVek%3D"/
end
@@ -61,7 +107,7 @@
request = Request.new :get, Addressable::URI.parse("http://xxx/?a=b")
authorized_request = OAuthPolicy.authorize request
-
+
authorized_request.headers["Authorization"].should =~ /oauth_signature="DprU1bdbNdJQ40UhD4n7wRR9jts%3D"/
end
4 spec/organization_spec.rb
View
@@ -6,7 +6,7 @@ module Trello
include Helpers
before(:each) do
- Client.stub(:get).with("/organizations/4ee7e59ae582acdec8000291").
+ Trello.client.stub(:get).with("/organizations/4ee7e59ae582acdec8000291").
and_return organization_payload
@organization = Organization.find('4ee7e59ae582acdec8000291')
@@ -14,7 +14,7 @@ module Trello
context "actions" do
it "retrieves actions" do
- Client.stub(:get).with("/organizations/4ee7e59ae582acdec8000291/actions", { :filter => :all }).and_return actions_payload
+ Trello.client.stub(:get).with("/organizations/4ee7e59ae582acdec8000291/actions", { :filter => :all }).and_return actions_payload
@organization.actions.count.should be > 0
end
6 spec/token_spec.rb
View
@@ -5,7 +5,7 @@ module Trello
include Helpers
before(:each) do
- Client.stub(:get).with("/tokens/1234").and_return token_payload
+ Trello.client.stub(:get).with("/tokens/1234").and_return token_payload
@token = Token.find("1234")
end
@@ -25,9 +25,9 @@ module Trello
context "members" do
it "retrieves the member who authorized the token" do
- Client.stub(:get).with("/members/abcdef123456789123456789").and_return user_payload
+ Trello.client.stub(:get).with("/members/abcdef123456789123456789").and_return user_payload
@token.member.should == Member.find("abcdef123456789123456789")
end
end
end
-end
+end
76 spec/trello_spec.rb
View
@@ -0,0 +1,76 @@
+require 'spec_helper'
+
+include Trello
+include Trello::Authorization
+
+describe Trello do
+ before do
+ Trello.reset!
+ end
+
+ describe "self.configure" do
+ it "builds auth policy client uses to make requests" do
+ Trello.configure do |config|
+ config.developer_public_key = 'developer_public_key'
+ config.member_token = 'member_token'
+ end
+
+ TInternet.stub(:execute)
+ Trello.auth_policy.should_receive(:authorize)
+ Trello.client.get(:member, params = {})