Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Support new API #9

Merged
merged 2 commits into from

2 participants

@anttipitkanen

New API update: support Chat posting and JSON responses. Deprecated old stuff.

@lautis lautis merged commit 7ae729c into master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 17, 2012
  1. New API update: support Chat posting and JSON responses. Deprecated o…

    Antti Pitkanen authored
    …ld API stuff.
  2. Allow parameter overriding in posting

    Antti Pitkanen authored
This page is out of date. Refresh to see the latest.
View
1  Gemfile
@@ -2,6 +2,7 @@ source "http://rubygems.org"
# Add dependencies required to use your gem here.
gem "httparty", "~> 0.7"
+gem "multi_json"
# Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc.
View
45 README.md
@@ -1,8 +1,6 @@
# Flowdock
-Ruby Gem for using the Flowdock API.
-
-http://www.flowdock.com/api
+Ruby Gem for using the Flowdock Push API. See [Push API documentation](http://www.flowdock.com/api/push) for details.
## Build Status
@@ -13,6 +11,7 @@ flowdock gem is tested on Ruby 1.8.7, 1.9.3 and JRuby.
## Requirements
* HTTParty
+* MultiJson
## Installing
@@ -20,18 +19,40 @@ flowdock gem is tested on Ruby 1.8.7, 1.9.3 and JRuby.
If you're using JRuby, you'll also need to install jruby-openssl gem.
-## Example
+## Posting to Chat
require 'rubygems'
require 'flowdock'
- # create a new Flow object with target flow's api token and sender information
+ # create a new Flow object with target flow's api token and external user name (enough for posting to Chat)
+ flow = Flowdock::Flow.new(:api_token => "56188e2003e370c6efa9711988f7bf02", :external_user_name => "John")
+
+ # send message to Chat
+ flow.push_to_chat(:content => "Hello!", :tags => ["cool", "stuff"])
+
+## Posting to Team Inbox
+
+ # create a new Flow object with target flow's api token and sender information for Team Inbox posting
flow = Flowdock::Flow.new(:api_token => "56188e2003e370c6efa9711988f7bf02",
- :source => "myapp",
- :from => {:name => "John Doe", :address => "john.doe@example.com"})
+ :source => "myapp", :from => {:name => "John Doe", :address => "john.doe@example.com"})
- # send message to the flow
- flow.send_message(:subject => "Greetings from Flowdock API Gem!",
+ # send message to Team Inbox
+ flow.push_to_team_inbox(:subject => "Greetings from Flowdock API Gem!",
+ :content => "<h2>It works!</h2><p>Now you can start developing your awesome application for Flowdock.</p>",
+ :tags => ["cool", "stuff"], :link => "http://www.flowdock.com/")
+
+
+## Posting to both
+
+ # create a new Flow object with target flow's api token, external user name and sender information
+ flow = Flowdock::Flow.new(:api_token => "56188e2003e370c6efa9711988f7bf02", :external_user_name => "John",
+ :source => "myapp", :from => {:name => "John Doe", :address => "john.doe@example.com"})
+
+ # send message to Chat
+ flow.push_to_chat(:content => "Hello!", :tags => ["cool", "stuff"])
+
+ # send message to Team Inbox
+ flow.push_to_team_inbox(:subject => "Greetings from Flowdock API Gem!",
:content => "<h2>It works!</h2><p>Now you can start developing your awesome application for Flowdock.</p>",
:tags => ["cool", "stuff"], :link => "http://www.flowdock.com/")
@@ -39,7 +60,11 @@ If you're using JRuby, you'll also need to install jruby-openssl gem.
* Flow methods
- *send_message(params)* - Send message to flow. See [API documentation](http://www.flowdock.com/help/api_documentation) for details.
+ *push_to_team_inbox* - Send message to Team Inbox. See [API documentation](http://www.flowdock.com/api/team-inbox) for details.
+
+ *push_to_chat* - Send message to Chat. See [API documentation](http://www.flowdock.com/api/chat) for details.
+
+ *send_message(params)* - Deprecated. Please use *push_to_team_inbox* instead.
## Capistrano deployment task
View
76 lib/flowdock.rb
@@ -1,33 +1,37 @@
require 'rubygems'
require 'httparty'
+require 'multi_json'
module Flowdock
- FLOWDOCK_API_URL = "https://api.flowdock.com/v1/messages/influx"
+ FLOWDOCK_API_URL = "https://api.flowdock.com/v1"
class Flow
include HTTParty
class InvalidParameterError < StandardError; end
class ApiError < StandardError; end
- # Required options keys: :api_token, :source, :from => { :name, :address }
+ # Required options keys: :api_token, optional keys: :external_user_name, :source, :from => { :name, :address }
def initialize(options = {})
@api_token = options[:api_token]
raise InvalidParameterError, "Flow must have :api_token attribute" if blank?(@api_token)
- @source = options[:source]
- raise InvalidParameterError, "Flow must have valid :source attribute, only alphanumeric characters and underscores can be used" if blank?(@source) || !@source.match(/^[a-z0-9\-_ ]+$/i)
-
- @project = options[:project]
- raise InvalidParameterError, "Optional attribute :project can only contain alphanumeric characters and underscores" if !blank?(@project) && !@project.match(/^[a-z0-9\-_ ]+$/i)
-
+ @source = options[:source] || nil
+ @project = options[:project] || nil
@from = options[:from] || {}
+ @external_user_name = options[:external_user_name] || nil
end
- def send_message(params)
+ def push_to_team_inbox(params)
+ @source = params[:source] unless blank?(params[:source])
+ raise InvalidParameterError, "Message must have valid :source attribute, only alphanumeric characters and underscores can be used" if blank?(@source) || !@source.match(/^[a-z0-9\-_ ]+$/i)
+
+ @project = params[:project] unless blank?(params[:project])
+ raise InvalidParameterError, "Optional attribute :project can only contain alphanumeric characters and underscores" if !blank?(@project) && !@project.match(/^[a-z0-9\-_ ]+$/i)
+
raise InvalidParameterError, "Message must have both :subject and :content" if blank?(params[:subject]) || blank?(params[:content])
from = (params[:from].kind_of?(Hash)) ? params[:from] : @from
- raise InvalidParameterError, "Flow's :from attribute must have :address attribute" if blank?(from[:address])
+ raise InvalidParameterError, "Message's :from attribute must have :address attribute" if blank?(from[:address])
tags = (params[:tags].kind_of?(Array)) ? params[:tags] : []
tags.reject! { |tag| !tag.kind_of?(String) || blank?(tag) }
@@ -37,29 +41,71 @@ def send_message(params)
params = {
:source => @source,
:format => 'html', # currently only supported format
- :from_name => from[:name],
:from_address => from[:address],
:subject => params[:subject],
:content => params[:content],
}
+ params[:from_name] = from[:name] unless blank?(from[:name])
params[:tags] = tags.join(",") if tags.size > 0
params[:project] = @project unless blank?(@project)
params[:link] = link unless blank?(link)
# Send the request
- resp = self.class.post(get_flowdock_api_url, :body => params)
- raise ApiError, "Flowdock API returned error: Status: #{resp.code} Body: #{resp.body}" unless resp.code == 200
+ resp = self.class.post(get_flowdock_api_url("messages/team_inbox"), :body => params)
+ handle_response(resp)
+ true
+ end
+
+ def push_to_chat(params)
+ raise InvalidParameterError, "Message must have :content" if blank?(params[:content])
+
+ @external_user_name = params[:external_user_name] unless blank?(params[:external_user_name])
+ if blank?(@external_user_name) || @external_user_name.match(/^[\S]+$/).nil? || @external_user_name.length > 16
+ raise InvalidParameterError, "Message must have :external_user_name that has no whitespace and maximum of 16 characters"
+ end
+
+ tags = (params[:tags].kind_of?(Array)) ? params[:tags] : []
+ tags.reject! { |tag| !tag.kind_of?(String) || blank?(tag) }
+
+ params = {
+ :content => params[:content],
+ :external_user_name => @external_user_name
+ }
+ params[:tags] = tags.join(",") if tags.size > 0
+
+ # Send the request
+ resp = self.class.post(get_flowdock_api_url("messages/chat"), :body => params)
+ handle_response(resp)
true
end
+ # <b>DEPRECATED:</b> Please use <tt>useful</tt> instead.
+ def send_message(params)
+ warn "[DEPRECATION] `send_message` is deprecated. Please use `push_to_team_inbox` instead."
+ push_to_team_inbox(params)
+ end
+
private
def blank?(var)
var.nil? || var.respond_to?(:length) && var.length == 0
end
- def get_flowdock_api_url
- "#{FLOWDOCK_API_URL}/#{@api_token}"
+ def handle_response(resp)
+ unless resp.code == 200
+ begin
+ # should have JSON response
+ json = MultiJson.decode(resp.body)
+ errors = json["errors"].map {|k,v| "#{k}: #{v.join(',')}"}.join("\n") unless json["errors"].nil?
+ raise ApiError, "Flowdock API returned error:\nStatus: #{resp.code}\n Message: #{json["message"]}\n Errors:\n#{errors}"
+ rescue MultiJson::DecodeError
+ raise ApiError, "Flowdock API returned error:\nStatus: #{resp.code}\nBody: #{resp.body}"
+ end
+ end
+ end
+
+ def get_flowdock_api_url(path)
+ "#{FLOWDOCK_API_URL}/#{path}/#{@api_token}"
end
end
end
View
2  lib/flowdock/capistrano.rb
@@ -42,7 +42,7 @@
task :notify_deploy_finished do
# send message to the flow
begin
- flowdock_api.send_message(:format => "html",
+ flowdock_api.push_to_team_inbox(:format => "html",
:subject => "#{flowdock_project_name} deployed with branch #{branch} on ##{rails_env}",
:content => notification_message,
:tags => ["deploy", "#{rails_env}"] | flowdock_deploy_tags)
View
213 spec/flowdock_spec.rb
@@ -2,88 +2,132 @@
describe Flowdock do
describe "with initializing flow" do
- it "should succeed with correct token and source" do
+ it "should succeed with correct token" do
lambda {
- @flow = Flowdock::Flow.new(:api_token => "test", :source => "myapp")
+ @flow = Flowdock::Flow.new(:api_token => "test")
}.should_not raise_error
end
- it "should succeed with correct token, source and sender information" do
+ it "should fail without token" do
lambda {
- @flow = Flowdock::Flow.new(:api_token => "test", :source => "myapp",
- :from => {:name => "test", :address => "invalid@nodeta.fi"})
- }.should_not raise_error
+ @flow = Flowdock::Flow.new(:api_token => "")
+ }.should raise_error(Flowdock::Flow::InvalidParameterError)
end
+ end
- it "should succeed with correct token, sender information, source and project" do
- lambda {
- @flow = Flowdock::Flow.new(:api_token => "test", :source => "myapp", :project => "myproject",
- :from => {:name => "test", :address => "invalid@nodeta.fi"})
- }.should_not raise_error
+ describe "with sending Team Inbox messages" do
+ before(:each) do
+ @token = "test"
+ @flow_attributes = {:api_token => @token, :source => "myapp", :project => "myproject",
+ :from => {:name => "Eric Example", :address => "eric@example.com"}}
+ @flow = Flowdock::Flow.new(@flow_attributes)
+ @example_content = "<h1>Hello</h1>\n<p>Let's rock and roll!</p>"
+ @valid_attributes = {:subject => "Hello World", :content => @example_content,
+ :link => "http://www.flowdock.com/", :tags => ["cool", "stuff"]}
end
- it "should succeed without the optional from-name parameter" do
+ it "should not send without source" do
lambda {
- @flow = Flowdock::Flow.new(:api_token => "test", :source => "myapp",
- :from => {:address => "invalid@nodeta.fi"})
- }.should_not raise_error
+ @flow = Flowdock::Flow.new(@flow_attributes.merge(:source => ""))
+ @flow.push_to_team_inbox(@valid_attributes)
+ }.should raise_error(Flowdock::Flow::InvalidParameterError)
end
- it "should fail without token" do
+ it "should not send when source is not alphanumeric" do
lambda {
- @flow = Flowdock::Flow.new(:api_token => "", :source => "myapp")
+ @flow = Flowdock::Flow.new(@flow_attributes.merge(:source => "$foobar"))
+ @flow.push_to_team_inbox(@valid_attributes)
}.should raise_error(Flowdock::Flow::InvalidParameterError)
end
- it "should fail without source" do
+ it "should not send when project is not alphanumeric" do
lambda {
- @flow = Flowdock::Flow.new(:api_token => "test", :source => "")
+ @flow = Flowdock::Flow.new(:api_token => "test", :source => "myapp", :project => "$foobar")
+ @flow.push_to_team_inbox(@valid_attributes)
}.should raise_error(Flowdock::Flow::InvalidParameterError)
end
- it "should fail when source is not alphanumeric" do
+ it "should not send without sender information" do
lambda {
- @flow = Flowdock::Flow.new(:api_token => "test", :source => "$foobar")
+ @flow = Flowdock::Flow.new(@flow_attributes.merge(:from => nil))
+ @flow.push_to_team_inbox(@valid_attributes)
}.should raise_error(Flowdock::Flow::InvalidParameterError)
end
- it "should fail when project is not alphanumeric" do
+ it "should not send without subject" do
lambda {
- @flow = Flowdock::Flow.new(:api_token => "test", :source => "myapp", :project => "$foobar")
+ @flow.push_to_team_inbox(@valid_attributes.merge(:subject => ""))
}.should raise_error(Flowdock::Flow::InvalidParameterError)
end
- end
- describe "with sending messages" do
- before(:each) do
- @token = "test"
- @flow = Flowdock::Flow.new(:api_token => @token, :source => "myapp", :project => "myproject",
- :from => {:name => "Eric Example", :address => "eric@example.com"})
- @example_content = "<h1>Hello</h1>\n<p>Let's rock and roll!</p>"
+ it "should not send without content" do
+ lambda {
+ @flow.push_to_team_inbox(@valid_attributes.merge(:content => ""))
+ }.should raise_error(Flowdock::Flow::InvalidParameterError)
end
- it "should not send without subject" do
+ it "should succeed with correct token, source and sender information" do
lambda {
- @flow.send_message(:subject => "", :content => "Test")
- }.should raise_error(Flowdock::Flow::InvalidParameterError)
+ stub_request(:post, push_to_team_inbox_url(@token)).
+ with(:body => {
+ :source => "myapp",
+ :format => "html",
+ :from_name => "Eric Example",
+ :from_address => "eric@example.com",
+ :subject => "Hello World",
+ :content => @example_content,
+ :tags => "cool,stuff",
+ :link => "http://www.flowdock.com/"
+ }).
+ to_return(:body => "", :status => 200)
+
+ @flow = Flowdock::Flow.new(@flow_attributes.merge(:project => ""))
+ @flow.push_to_team_inbox(@valid_attributes)
+ }.should_not raise_error
end
- it "should not send without content" do
+ it "should succeed without the optional from-name parameter" do
lambda {
- @flow.send_message(:subject => "Test", :content => "")
- }.should raise_error(Flowdock::Flow::InvalidParameterError)
+ stub_request(:post, push_to_team_inbox_url(@token)).
+ with(:body => {
+ :source => "myapp",
+ :project => "myproject",
+ :format => "html",
+ :from_address => "eric@example.com",
+ :subject => "Hello World",
+ :content => @example_content,
+ :tags => "cool,stuff",
+ :link => "http://www.flowdock.com/"
+ }).
+ to_return(:body => "", :status => 200)
+ @flow = Flowdock::Flow.new(@flow_attributes.merge(:from => {:address => "eric@example.com"}))
+ @flow.push_to_team_inbox(@valid_attributes)
+ }.should_not raise_error
end
- it "should not send without sender information" do
- @flow = Flowdock::Flow.new(:api_token => @token, :source => "myapp")
+ it "should succeed with correct token, sender information, source and project" do
lambda {
- @flow.send_message(:subject => "Test", :content => @example_content)
- }.should raise_error(Flowdock::Flow::InvalidParameterError)
+ stub_request(:post, push_to_team_inbox_url(@token)).
+ with(:body => {
+ :source => "myapp",
+ :project => "myproject",
+ :format => "html",
+ :from_name => "Eric Example",
+ :from_address => "eric@example.com",
+ :subject => "Hello World",
+ :content => @example_content,
+ :tags => "cool,stuff",
+ :link => "http://www.flowdock.com/"
+ }).
+ to_return(:body => "", :status => 200)
+ @flow = Flowdock::Flow.new(@flow_attributes)
+ @flow.push_to_team_inbox(@valid_attributes)
+ }.should_not raise_error
end
it "should send with valid parameters and return true" do
lambda {
- stub_request(:post, "#{Flowdock::FLOWDOCK_API_URL}/#{@token}").
+ stub_request(:post, push_to_team_inbox_url(@token)).
with(:body => {
:source => "myapp",
:project => "myproject",
@@ -97,14 +141,14 @@
}).
to_return(:body => "", :status => 200)
- @flow.send_message(:subject => "Hello World", :content => @example_content,
+ @flow.push_to_team_inbox(:subject => "Hello World", :content => @example_content,
:tags => ["cool", "stuff"], :link => "http://www.flowdock.com/").should be_true
}.should_not raise_error
end
it "should allow overriding sender information per message" do
lambda {
- stub_request(:post, "#{Flowdock::FLOWDOCK_API_URL}/#{@token}").
+ stub_request(:post, push_to_team_inbox_url(@token)).
with(:body => {
:source => "myapp",
:project => "myproject",
@@ -117,14 +161,14 @@
}).
to_return(:body => "", :status => 200)
- @flow.send_message(:subject => "Hello World", :content => @example_content, :tags => ["cool", "stuff"],
+ @flow.push_to_team_inbox(:subject => "Hello World", :content => @example_content, :tags => ["cool", "stuff"],
:from => {:name => "Test", :address => "invalid@nodeta.fi"}).should be_true
}.should_not raise_error
end
it "should raise error if backend returns anything but 200 OK" do
lambda {
- stub_request(:post, "#{Flowdock::FLOWDOCK_API_URL}/#{@token}").
+ stub_request(:post, push_to_team_inbox_url(@token)).
with(:body => {
:source => "myapp",
:project => "myproject",
@@ -136,8 +180,85 @@
}).
to_return(:body => "Internal Server Error", :status => 500)
- @flow.send_message(:subject => "Hello World", :content => @example_content).should be_false
+ @flow.push_to_team_inbox(:subject => "Hello World", :content => @example_content).should be_false
+ }.should raise_error(Flowdock::Flow::ApiError)
+ end
+ end
+
+ describe "with sending Chat messages" do
+ before(:each) do
+ @token = "test"
+ @flow = Flowdock::Flow.new(:api_token => @token)
+ @valid_parameters = {:external_user_name => "foobar", :content => "Hello", :tags => ["cool","stuff"]}
+ end
+
+ it "should not send without content" do
+ lambda {
+ @flow.push_to_chat(@valid_parameters.merge(:content => ""))
+ }.should raise_error(Flowdock::Flow::InvalidParameterError)
+ end
+
+ it "should not send without external_user_name" do
+ lambda {
+ @flow.push_to_chat(@valid_parameters.merge(:external_user_name => ""))
+ }.should raise_error(Flowdock::Flow::InvalidParameterError)
+ end
+
+ it "should not send with invalid external_user_name" do
+ lambda {
+ @flow.push_to_chat(@valid_parameters.merge(:external_user_name => "foo bar"))
+ }.should raise_error(Flowdock::Flow::InvalidParameterError)
+ end
+
+ it "should send with valid parameters and return true" do
+ lambda {
+ stub_request(:post, push_to_chat_url(@token)).
+ with(:body => @valid_parameters.merge(:tags => "cool,stuff")).
+ to_return(:body => "", :status => 200)
+
+ @flow.push_to_chat(@valid_parameters).should be_true
+ }.should_not raise_error
+ end
+
+ it "should accept external_user_name in init" do
+ lambda {
+ stub_request(:post, push_to_chat_url(@token)).
+ with(:body => @valid_parameters.merge(:tags => "cool,stuff", :external_user_name => "foobar2")).
+ to_return(:body => "", :status => 200)
+
+ @flow = Flowdock::Flow.new(:api_token => @token, :external_user_name => "foobar")
+ @flow.push_to_chat(@valid_parameters.merge(:external_user_name => "foobar2"))
+ }.should_not raise_error
+ end
+
+ it "should allow overriding external_user_name" do
+ lambda {
+ stub_request(:post, push_to_chat_url(@token)).
+ with(:body => @valid_parameters.merge(:tags => "cool,stuff")).
+ to_return(:body => "", :status => 200)
+
+ @flow = Flowdock::Flow.new(:api_token => @token, :external_user_name => "foobar")
+ @flow.push_to_chat(@valid_parameters.merge(:external_user_name => ""))
+ }.should_not raise_error
+ end
+
+ it "should raise error if backend returns anything but 200 OK" do
+ lambda {
+ stub_request(:post, push_to_chat_url(@token)).
+ with(:body => @valid_parameters.merge(:tags => "cool,stuff")).
+ to_return(:body => '{"message":"Validation error","errors":{"content":["can\'t be blank"],"external_user_name":["should not contain whitespace"]}}',
+ :status => 400)
+
+ @flow.push_to_chat(@valid_parameters).should be_false
}.should raise_error(Flowdock::Flow::ApiError)
end
end
+
+ def push_to_chat_url(token)
+ "#{Flowdock::FLOWDOCK_API_URL}/messages/chat/#{token}"
+ end
+
+ def push_to_team_inbox_url(token)
+ "#{Flowdock::FLOWDOCK_API_URL}/messages/team_inbox/#{token}"
+ end
end
Something went wrong with that request. Please try again.