flowdock-0.7.0/0000755000175600017570000000000012632523357012377 5ustar pravipraviflowdock-0.7.0/spec/0000755000175600017570000000000012632523356013330 5ustar pravipraviflowdock-0.7.0/spec/spec_helper.rb0000644000175600017570000000057512632523356016155 0ustar pravipravi$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $LOAD_PATH.unshift(File.dirname(__FILE__)) require 'rspec' require 'webmock/rspec' require 'flowdock' # Requires supporting files with custom matchers and macros, etc, # in ./support/ and its subdirectories. Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f} RSpec.configure do |config| end flowdock-0.7.0/spec/flowdock_spec.rb0000644000175600017570000004404412632523356016505 0ustar pravipravirequire 'spec_helper' describe Flowdock do describe "with initializing flow" do it "should succeed with correct token" do lambda { @flow = Flowdock::Flow.new(:api_token => "test") }.should_not raise_error end it "should fail without token" do lambda { @flow = Flowdock::Flow.new(:api_token => "") }.should raise_error(Flowdock::InvalidParameterError) end it "should succeed with array of tokens" do lambda { @flow = Flowdock::Flow.new(:api_token => ["test", "foobar"]) }.should_not raise_error end end 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"}, :reply_to => "john@example.com" } @flow = Flowdock::Flow.new(@flow_attributes) @example_content = "

Hello

\n

Let's rock and roll!

" @valid_attributes = {:subject => "Hello World", :content => @example_content, :link => "http://www.flowdock.com/", :tags => ["cool", "stuff"]} end it "should not send without source" do lambda { @flow = Flowdock::Flow.new(@flow_attributes.merge(:source => "")) @flow.push_to_team_inbox(@valid_attributes) }.should raise_error(Flowdock::InvalidParameterError) end it "should not send when source is not alphanumeric" do lambda { @flow = Flowdock::Flow.new(@flow_attributes.merge(:source => "$foobar")) @flow.push_to_team_inbox(@valid_attributes) }.should raise_error(Flowdock::InvalidParameterError) end it "should not send when project is not alphanumeric" do lambda { @flow = Flowdock::Flow.new(:api_token => "test", :source => "myapp", :project => "$foobar") @flow.push_to_team_inbox(@valid_attributes) }.should raise_error(Flowdock::InvalidParameterError) end it "should not send without sender information" do lambda { @flow = Flowdock::Flow.new(@flow_attributes.merge(:from => nil)) @flow.push_to_team_inbox(@valid_attributes) }.should raise_error(Flowdock::InvalidParameterError) end it "should not send without subject" do lambda { @flow.push_to_team_inbox(@valid_attributes.merge(:subject => "")) }.should raise_error(Flowdock::InvalidParameterError) end it "should not send without content" do lambda { @flow.push_to_team_inbox(@valid_attributes.merge(:content => "")) }.should raise_error(Flowdock::InvalidParameterError) end it "should send without reply_to address" do expect { stub_request(:post, push_to_team_inbox_url(@token)).to_return(:body => "", :status => 200) @flow.push_to_team_inbox(@valid_attributes.merge(:reply_to => "")) }.not_to raise_error end it "should succeed with correct token, source and sender information" do lambda { stub_request(:post, push_to_team_inbox_url(@token)). with(:body => { :source => "myapp", :format => "html", :from_name => "Eric Example", :from_address => "eric@example.com", :reply_to => "john@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 succeed with correct params and multiple tokens" do lambda { tokens = ["test", "foobar"] stub_request(:post, push_to_team_inbox_url(tokens)). with(:body => { :source => "myapp", :format => "html", :from_name => "Eric Example", :from_address => "eric@example.com", :reply_to => "john@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 => "", :api_token => tokens)) @flow.push_to_team_inbox(@valid_attributes) }.should_not raise_error end it "should succeed without the optional from-name parameter" do lambda { stub_request(:post, push_to_team_inbox_url(@token)). with(:body => { :source => "myapp", :project => "myproject", :format => "html", :from_address => "eric@example.com", :reply_to => "john@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 succeed with correct token, sender information, source and project" do lambda { 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", :reply_to => "john@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, push_to_team_inbox_url(@token)). with(:body => { :source => "myapp", :project => "myproject", :format => "html", :from_name => "Eric Example", :from_address => "eric@example.com", :reply_to => "john@example.com", :subject => "Hello World", :content => @example_content, :tags => "cool,stuff", :link => "http://www.flowdock.com/" }). to_return(:body => "", :status => 200) @flow.push_to_team_inbox(:subject => "Hello World", :content => @example_content, :tags => ["cool", "stuff"], :link => "http://www.flowdock.com/").should be_truthy }.should_not raise_error end it "should allow overriding sender information per message" do lambda { stub_request(:post, push_to_team_inbox_url(@token)). with(:body => { :source => "myapp", :project => "myproject", :format => "html", :from_name => "Test", :from_address => "invalid@nodeta.fi", :reply_to => "foobar@example.com", :subject => "Hello World", :content => @example_content, :tags => "cool,stuff", }). to_return(:body => "", :status => 200) @flow.push_to_team_inbox(:subject => "Hello World", :content => @example_content, :tags => ["cool", "stuff"], :from => {:name => "Test", :address => "invalid@nodeta.fi"}, :reply_to => "foobar@example.com").should be_truthy }.should_not raise_error end it "should raise error if backend returns anything but 200 OK" do lambda { 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", :reply_to => "john@example.com", :subject => "Hello World", :content => @example_content }). to_return(:body => "Internal Server Error", :status => 500) @flow.push_to_team_inbox(:subject => "Hello World", :content => @example_content).should be_false }.should raise_error(Flowdock::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::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::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::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_truthy }.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::ApiError) end it "should send supplied message to create comments" do lambda { stub_request(:post, push_to_chat_url(@token)). with(:body => /message_id=12345/). to_return(:body => "", :status => 200) @flow = Flowdock::Flow.new(:api_token => @token, :external_user_name => "foobar") @flow.push_to_chat(@valid_parameters.merge(:message_id => 12345)) }.should_not raise_error end it "should send supplied thread_id to post to threads" do lambda { stub_request(:post, push_to_chat_url(@token)). with(:body => /thread_id=acdcabbacd/). to_return(:body => "", :status => 200) @flow = Flowdock::Flow.new(:api_token => @token, :external_user_name => "foobar") @flow.push_to_chat(@valid_parameters.merge(:thread_id => 'acdcabbacd')) }.should_not raise_error end end def push_to_chat_url(token) "#{Flowdock::FLOWDOCK_API_URL}/messages/chat/#{join_tokens(token)}" end def push_to_team_inbox_url(token) "#{Flowdock::FLOWDOCK_API_URL}/messages/team_inbox/#{join_tokens(token)}" end def join_tokens(tokens) if tokens.kind_of?(Array) tokens.join(",") else tokens.to_s end end end describe Flowdock::Client do context "with flow_token" do let(:token) { SecureRandom.hex } let(:client) { Flowdock::Client.new(flow_token: token) } let(:flow) { SecureRandom.hex } describe "post a threaded message" do it "succeeds" do stub_request(:post, "https://api.flowdock.com/v1/messages"). with(body: MultiJson.dump(flow: flow, flow_token: token), headers: {"Accept" => "application/json", "Content-Type" => "application/json"}). to_return(status: 201, body: '{"id":123}', headers: {"Content-Type" => "application/json"}) res = client.post_to_thread({flow: flow}) expect(res).to eq({"id" => 123}) end end end context "with api_token" do let(:token) { SecureRandom.hex(8) } let(:client) { Flowdock::Client.new(api_token: token) } describe 'initializing' do it 'should initialize with access token' do expect { client = Flowdock::Client.new(api_token: token) expect(client.api_token).to equal(token) }.not_to raise_error end it 'should raise error if initialized without access token' do expect { client = Flowdock::Client.new(api_token: nil) }.to raise_error(Flowdock::InvalidParameterError) end end describe 'posting to chat' do let(:flow) { SecureRandom.hex(8) } it 'posts to /messages' do expect { stub_request(:post, "https://#{token}:@api.flowdock.com/v1/messages"). with(:body => MultiJson.dump(flow: flow, content: "foobar", tags: [], event: "message"), :headers => {"Accept" => "application/json", "Content-Type" => "application/json"}). to_return(:status => 201, :body => '{"id":123}', :headers => {"Content-Type" => "application/json"}) res = client.chat_message(flow: flow, content: 'foobar') expect(res).to eq({"id" => 123}) }.not_to raise_error end it 'posts to /comments' do expect { stub_request(:post, "https://#{token}:@api.flowdock.com/v1/comments"). with(:body => MultiJson.dump(flow: flow, content: "foobar", message: 12345, tags: [], event: "comment"), :headers => {"Accept" => "application/json", "Content-Type" => "application/json"}). to_return(:status => 201, :body => '{"id":1234}', :headers => {"Content-Type" => "application/json"}) res = client.chat_message(flow: flow, content: 'foobar', message: 12345) expect(res).to eq({"id" => 1234}) }.not_to raise_error end it 'posts to /private/:user_id/messages' do expect { stub_request(:post, "https://#{token}:@api.flowdock.com/v1/private/12345/messages"). with(:body => MultiJson.dump(content: "foobar", event: "message"), :headers => {"Accept" => "application/json", "Content-Type" => "application/json"}). to_return(:status => 201, :body => '{"id":1234}', :headers => {"Content-Type" => "application/json"}) res = client.private_message(user_id: "12345", content: 'foobar') expect(res).to eq({"id" => 1234}) }.not_to raise_error end it 'raises without flow' do expect { client.chat_message(content: 'foobar') }.to raise_error(Flowdock::InvalidParameterError) end it 'raises without content' do expect { client.chat_message(flow: flow) }.to raise_error(Flowdock::InvalidParameterError) end it 'handles error responses' do expect { stub_request(:post, "https://#{token}:@api.flowdock.com/v1/messages"). to_return(:body => '{"message":"Validation error","errors":{"content":["can\'t be blank"],"external_user_name":["should not contain whitespace"]}}', :status => 400) client.chat_message(flow: flow, content: 'foobar') }.to raise_error(Flowdock::ApiError) end end describe 'GET' do it 'does abstract get with params' do stub_request(:get, "https://#{token}:@api.flowdock.com/v1/some_path?sort_by=date"). with(:headers => {'Accept'=>'application/json', 'Content-Type'=>'application/json'}). to_return(:status => 200, :body => '{"id": 123}', :headers => {"Content-Type" => "application/json"}) expect(client.get('/some_path', {sort_by: 'date'})).to eq({"id" => 123}) end end describe 'POST' do it 'does abstract post with body' do stub_request(:post, "https://#{token}:@api.flowdock.com/v1/other_path"). with(:headers => {'Accept'=>'application/json', 'Content-Type'=>'application/json'}, :body => MultiJson.dump(name: 'foobar')). to_return(:status => 200, :body => '{"id": 123,"name": "foobar"}', :headers => {"Content-Type" => "application/json"}) expect(client.post('other_path', {name: 'foobar'})).to eq({"id" => 123, "name" => "foobar"}) end end describe 'PUT' do it 'does abstract put with body' do stub_request(:put, "https://#{token}:@api.flowdock.com/v1/other_path"). with(:headers => {'Accept'=>'application/json', 'Content-Type'=>'application/json'}, :body => MultiJson.dump(name: 'foobar')). to_return(:status => 200, :body => '{"id": 123,"name": "foobar"}', :headers => {"Content-Type" => "application/json"}) expect(client.put('other_path', {name: 'foobar'})).to eq({"id" => 123, "name" => "foobar"}) end end describe 'DELETE' do it 'does abstract delete with params' do stub_request(:delete, "https://#{token}:@api.flowdock.com/v1/some_path"). with(:headers => {'Accept'=>'application/json', 'Content-Type'=>'application/json'}). to_return(:status => 200, :body => '', :headers => {"Content-Type" => "application/json"}) expect(client.delete('/some_path')).to eq({}) end end end end flowdock-0.7.0/LICENSE0000644000175600017570000000204012632523356013377 0ustar pravipraviCopyright (c) 2012 Flowdock Ltd Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. flowdock-0.7.0/VERSION0000644000175600017570000000000512632523356013441 0ustar pravipravi0.7.0flowdock-0.7.0/.rspec0000644000175600017570000000000712632523356013510 0ustar pravipravi--colorflowdock-0.7.0/.travis.yml0000644000175600017570000000004712632523356014510 0ustar pravipravirvm: - 2.0 - 2.1 - 2.2 - jruby flowdock-0.7.0/.document0000644000175600017570000000006712632523356014220 0ustar pravipravilib/**/*.rb bin/* - features/**/*.feature MIT-LICENSE flowdock-0.7.0/README.md0000644000175600017570000001357712632523356013672 0ustar pravipravi# Flowdock Ruby gem for using the Flowdock Push API. See the [Push API documentation](http://www.flowdock.com/api/push) for details. ## Build Status [![Build Status](https://secure.travis-ci.org/flowdock/flowdock-api.png)](http://travis-ci.org/flowdock/flowdock-api) The Flowdock gem is tested on Ruby 2.1 and JRuby. ## Dependencies * HTTParty * MultiJson ## Installing gem install flowdock If you're using JRuby, you'll also need to install the `jruby-openssl` gem. ## Usage To post content to a flow's chat or team inbox using `Flowdock::Flow`, you need to use the target flow's API token or a source's flow_token. Alternatively, you can use your personal API token and the `Flowdock::Client`. Personal and flow's tokens can be found on the [tokens page](https://www.flowdock.com/account/tokens). ### REST API To create an API client, you need your personal [API token](https://flowdock.com/account/tokens), an [OAuth token](https://www.flowdock.com/api/authentication) or a [source's flow_token](https://www.flowdock.com/api/sources). Note that a `flow_token` will only allow you to post [thread messages](https://www.flowdock.com/api/production-integrations#/post-inbox) to the flow that the source belongs to. ```ruby require 'rubygems' require 'flowdock' # Create a client that uses your personal API token to authenticate api_token_client = Flowdock::Client.new(api_token: '__MY_PERSONAL_API_TOKEN__') # Create a client that uses a source's flow_token to authenticate. Can only use post_to_thread flow_token_client = Flowdock::Client.new(flow_token: '__FLOW_TOKEN__') ``` #### Posting to Chat To send a chat message or comment, you can use `client.chat_message`: ```ruby flow_id = 'acdcabbacd0123456789' # Send a simple chat message api_token_client.chat_message(flow: flow_id, content: "I'm sending a message!", tags: ['foo', 'bar']) # Send a comment to message 1234 api_token_client.chat_message(flow: flow_id, content: "Now I'm commenting!", message: 1234) ``` Both methods return the created message as a hash. #### Post a threaded messages You can post `activity` and `discussion` events to a [threaded conversation](https://www.flowdock.com/api/integration-getting-started) in Flowdock. ``` flow_token_client.post_to_thread( event: "activity", author: { name: "anttipitkanen", avatar: "https://avatars.githubusercontent.com/u/946511?v=2", }, title: "activity title", external_thread_id: "your-id-here", thread: { title: "this is required if you provide a thread field at all", body: "

some html content

", external_url: "https://example.com/issue/123", status: { color: "green", value: "open" } } } ``` #### Arbitary API access You can use the client to access the Flowdock API in other ways, too. See the [REST API documentation](http://www.flowdock.com/api/rest) for all the resources. ```ruby # Fetch all my flows flows = client.get('/flows') # Update a flow's name client.put('/flows/acme/my_flow', name: 'Your flow') # Delete a message client.delete('/flows/acme/my_flow/messages/12345') # Create an invitation client.post('/flows/acme/my_flow/invitations', email: 'user@example.com', message: "I'm inviting you to our flow using api.") ``` ### Push API **Note:** the Push API is in the process of being deprecated. [Creating a source](https://www.flowdock.com/api/integration-getting-started) along with a flow_token is recommended instead. To use the Push API, you need the flow's API token: #### Posting to the chat ```ruby require 'rubygems' require 'flowdock' # create a new Flow object with target flow's API token and external user name (enough for posting to the chat) flow = Flowdock::Flow.new(:api_token => "__FLOW_API_TOKEN__", :external_user_name => "John") # send message to Chat flow.push_to_chat(:content => "Hello!", :tags => ["cool", "stuff"]) ``` #### Posting to the team inbox ```ruby # create a new Flow object with the target flow's API token and sender information flow = Flowdock::Flow.new(:api_token => "__FLOW_API_TOKEN__", :source => "myapp", :from => {:name => "John Doe", :address => "john.doe@example.com"}) # send message to Team Inbox flow.push_to_team_inbox(:subject => "Greetings from the Flowdock API gem!", :content => "

It works!

Now you can start developing your awesome application for Flowdock.

", :tags => ["cool", "stuff"], :link => "http://www.flowdock.com/") ``` #### Posting to multiple flows ```ruby require 'rubygems' require 'flowdock' # create a new Flow object with the API tokens of the target flows flow = Flowdock::Flow.new(:api_token => ["__FLOW_API_TOKEN__", "__ANOTHER_FLOW_API_TOKEN__"], ... ) # see the above examples of posting to the chat or team inbox ``` ## API methods * `Flowdock::Flow` methods `push_to_team_inbox` - Send message to the team inbox. See [API documentation](http://www.flowdock.com/api/team-inbox) for details. `push_to_chat` - Send message to the chat. See [API documentation](http://www.flowdock.com/api/chat) for details. `send_message(params)` - Deprecated. Please use `push_to_team_inbox` instead. * `Flowdock::Client` methods `chat_message` - Send message to chat. `post_to_thread` - Post messages to a team inbox thread. `post`, `get`, `put`, `delete` - Send arbitary api calls. First parameter is the path, second is data. See [REST API documentation](http://www.flowdock.com/api/rest). ## Deployment notifications There are separate gems for deployment notifications: * [capistrano-flowdock](https://github.com/flowdock/capistrano-flowdock) * [mina-flowdock](https://github.com/elskwid/mina-flowdock) ## Changelog * 0.5.0 - Added `Flowdock::Client` that authenticates using user credentials and can be used to interact with the API. Better threads support for both `Flow` and `Client` so that comments can be made. ## Copyright Copyright (c) 2012 Flowdock Ltd. See LICENSE for further details. flowdock-0.7.0/flowdock.gemspec0000644000175600017570000000455112632523356015560 0ustar pravipravi# Generated by jeweler # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' # -*- encoding: utf-8 -*- # stub: flowdock 0.7.0 ruby lib Gem::Specification.new do |s| s.name = "flowdock" s.version = "0.7.0" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.require_paths = ["lib"] s.authors = ["Antti Pitk\u{e4}nen"] s.date = "2015-07-21" s.email = "team@flowdock.com" s.extra_rdoc_files = [ "LICENSE", "README.md" ] s.files = [ ".document", ".rspec", ".travis.yml", "Gemfile", "LICENSE", "README.md", "Rakefile", "VERSION", "flowdock.gemspec", "lib/flowdock.rb", "lib/flowdock/capistrano.rb", "spec/flowdock_spec.rb", "spec/spec_helper.rb" ] s.homepage = "http://github.com/flowdock/flowdock-api" s.licenses = ["MIT"] s.rubygems_version = "2.4.1" s.summary = "Ruby Gem for using Flowdock's API" if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_runtime_dependency(%q, ["~> 0.7"]) s.add_runtime_dependency(%q, [">= 0"]) s.add_development_dependency(%q, [">= 2.4.2"]) s.add_development_dependency(%q, ["~> 2.6"]) s.add_development_dependency(%q, [">= 0"]) s.add_development_dependency(%q, ["~> 1.0"]) s.add_development_dependency(%q, [">= 2.0.1"]) s.add_development_dependency(%q, [">= 0"]) else s.add_dependency(%q, ["~> 0.7"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 2.4.2"]) s.add_dependency(%q, ["~> 2.6"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, ["~> 1.0"]) s.add_dependency(%q, [">= 2.0.1"]) s.add_dependency(%q, [">= 0"]) end else s.add_dependency(%q, ["~> 0.7"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, [">= 2.4.2"]) s.add_dependency(%q, ["~> 2.6"]) s.add_dependency(%q, [">= 0"]) s.add_dependency(%q, ["~> 1.0"]) s.add_dependency(%q, [">= 2.0.1"]) s.add_dependency(%q, [">= 0"]) end end flowdock-0.7.0/Gemfile0000644000175600017570000000064412632523356013675 0ustar pravipravisource "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. group :development do gem "rdoc", ">= 2.4.2" gem "rspec", "~> 2.6" gem "webmock" gem "bundler", "~> 1.0" gem "jeweler", ">= 2.0.1" gem "jruby-openssl", :platforms => :jruby end flowdock-0.7.0/metadata.yml0000644000175600017570000000765612632523357014720 0ustar pravipravi--- !ruby/object:Gem::Specification name: flowdock version: !ruby/object:Gem::Version version: 0.7.0 platform: ruby authors: - Antti Pitkänen autorequire: bindir: bin cert_chain: [] date: 2015-07-21 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: httparty requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '0.7' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '0.7' - !ruby/object:Gem::Dependency name: multi_json requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rdoc requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 2.4.2 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 2.4.2 - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '2.6' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '2.6' - !ruby/object:Gem::Dependency name: webmock requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: bundler requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.0' - !ruby/object:Gem::Dependency name: jeweler requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 2.0.1 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 2.0.1 - !ruby/object:Gem::Dependency name: jruby-openssl requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' description: email: team@flowdock.com executables: [] extensions: [] extra_rdoc_files: - LICENSE - README.md files: - ".document" - ".rspec" - ".travis.yml" - Gemfile - LICENSE - README.md - Rakefile - VERSION - flowdock.gemspec - lib/flowdock.rb - lib/flowdock/capistrano.rb - spec/flowdock_spec.rb - spec/spec_helper.rb homepage: http://github.com/flowdock/flowdock-api licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.4.1 signing_key: specification_version: 4 summary: Ruby Gem for using Flowdock's API test_files: [] flowdock-0.7.0/lib/0000755000175600017570000000000012632523356013144 5ustar pravipraviflowdock-0.7.0/lib/flowdock.rb0000644000175600017570000001712012632523356015302 0ustar pravipravirequire 'rubygems' require 'httparty' require 'multi_json' module Flowdock FLOWDOCK_API_URL = "https://api.flowdock.com/v1" class InvalidParameterError < StandardError; end class ApiError < StandardError; end module Helpers def blank?(var) var.nil? || var.respond_to?(:length) && var.length == 0 end def handle_response(resp) json = MultiJson.decode(resp.body || '{}') unless resp.code >= 200 && resp.code < 300 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}" end json rescue MultiJson::DecodeError raise ApiError, "Flowdock API returned error:\nStatus: #{resp.code}\nBody: #{resp.body}" end end class Flow include HTTParty include Helpers attr_reader :api_token, :source, :project, :from, :external_user_name # Required options keys: :api_token # Optional keys: :external_user_name, :source, :project, :from => { :name, :address }, :reply_to def initialize(options = {}) @api_token = if options[:api_token].kind_of?(Array) options[:api_token].join(",") else options[:api_token].to_s end raise InvalidParameterError, "Flow must have :api_token attribute" if blank?(@api_token) @source = options[:source] || nil @project = options[:project] || nil @from = options[:from] || {} @reply_to = options[:reply_to] || nil @external_user_name = options[:external_user_name] || nil end 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, "Message's :from attribute must have :address attribute" if blank?(from[:address]) reply_to = (!blank?(params[:reply_to])) ? params[:reply_to] : @reply_to tags = (params[:tags].kind_of?(Array)) ? params[:tags] : [] tags.reject! { |tag| !tag.kind_of?(String) || blank?(tag) } link = (!blank?(params[:link])) ? params[:link] : nil params = { :source => @source, :format => 'html', # currently only supported format :from_address => from[:address], :subject => params[:subject], :content => params[:content], } params[:from_name] = from[:name] unless blank?(from[:name]) params[:reply_to] = reply_to unless blank?(reply_to) 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("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) } thread_id = params[:thread_id] message_id = params[:message_id] || params[:message] params = { :content => params[:content], :external_user_name => @external_user_name } params[:tags] = tags.join(",") if tags.size > 0 params[:thread_id] = thread_id if thread_id params[:message_id] = message_id if message_id # Send the request resp = self.class.post(get_flowdock_api_url("messages/chat"), :body => params) handle_response(resp) true end # DEPRECATED: Please use useful 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 get_flowdock_api_url(path) "#{FLOWDOCK_API_URL}/#{path}/#{@api_token}" end end class Client include HTTParty include Helpers attr_reader :api_token def initialize(options = {}) @api_token = options[:api_token] @flow_token = options[:flow_token] raise InvalidParameterError, "Client must have :api_token or an :flow_token" if blank?(@api_token) && blank?(@flow_token) end def chat_message(params) raise InvalidParameterError, "missing api_token" if blank?(@api_token) raise InvalidParameterError, "Message must have :content" if blank?(params[:content]) raise InvalidParameterError, "Message must have :flow" if blank?(params[:flow]) params = params.clone tags = (params[:tags].kind_of?(Array)) ? params[:tags] : [] params[:message] = params.delete(:message_id) if params[:message_id] tags.reject! { |tag| !tag.kind_of?(String) || blank?(tag) } event = if params[:message] then 'comment' else 'message' end post(event + 's', params.merge(tags: tags, event: event)) end def private_message(params) raise InvalidParameterError, "missing api_token" if blank?(@api_token) raise InvalidParameterError, "Message must have :content" if blank?(params[:content]) raise InvalidParameterError, "Message must have :user_id" if blank?(params[:user_id]) user_id = params.delete(:user_id) params = params.clone event = "message" post("private/#{user_id}/messages", params.merge(event: event)) end def post_to_thread(thread) raise InvalidParameterError, "missing flow_token" if blank?(@flow_token) resp = self.class.post(api_url("/messages"), body: MultiJson.dump(thread.merge(flow_token: @flow_token)), headers: headers) handle_response resp end def post(path, data = {}) resp = self.class.post(api_url(path), :body => MultiJson.dump(data), :basic_auth => {:username => @api_token, :password => ''}, :headers => headers) handle_response(resp) end def get(path, data = {}) resp = self.class.get(api_url(path), :query => data, :basic_auth => {:username => @api_token, :password => ''}, :headers => headers) handle_response(resp) end def put(path, data = {}) resp = self.class.put(api_url(path), :body => MultiJson.dump(data), :basic_auth => {:username => @api_token, :password => ''}, :headers => headers) handle_response(resp) end def delete(path) resp = self.class.delete(api_url(path), :basic_auth => {:username => @api_token, :password => ''}, :headers => headers) handle_response(resp) end private def api_url(path) File.join(FLOWDOCK_API_URL, path) end def headers {"Content-Type" => "application/json", "Accept" => "application/json"} end end end flowdock-0.7.0/lib/flowdock/0000755000175600017570000000000012632523356014754 5ustar pravipraviflowdock-0.7.0/lib/flowdock/capistrano.rb0000644000175600017570000000011312632523356017437 0ustar pravipraviwarn "Capistrano notifier has been extracted to `capistrano-flowdock` gem" flowdock-0.7.0/Rakefile0000644000175600017570000000215612632523356014047 0ustar pravipravi# encoding: utf-8 require 'rubygems' require 'bundler' begin Bundler.setup(:default, :development) rescue Bundler::BundlerError => e $stderr.puts e.message $stderr.puts "Run `bundle install` to install missing gems" exit e.status_code end require 'rake' require 'jeweler' Jeweler::Tasks.new do |gem| # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options gem.name = "flowdock" gem.homepage = "http://github.com/flowdock/flowdock-api" gem.license = "MIT" gem.summary = %Q{Ruby Gem for using Flowdock's API} gem.email = "team@flowdock.com" gem.authors = ["Antti Pitkänen"] # dependencies defined in Gemfile end Jeweler::RubygemsDotOrgTasks.new require 'rspec/core' require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) do |spec| spec.pattern = FileList['spec/**/*_spec.rb'] end task :default => :spec require 'rdoc/task' RDoc::Task.new do |rdoc| version = File.exist?('VERSION') ? File.read('VERSION') : "" rdoc.rdoc_dir = 'rdoc' rdoc.title = "flowdock #{version}" rdoc.rdoc_files.include('README*') rdoc.rdoc_files.include('lib/**/*.rb') end