├── .document ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── VERSION ├── lib ├── pipedrive-ruby.rb └── pipedrive │ ├── activity-type.rb │ ├── activity.rb │ ├── authorization.rb │ ├── base.rb │ ├── currency.rb │ ├── deal-field.rb │ ├── deal.rb │ ├── file.rb │ ├── filter.rb │ ├── goal.rb │ ├── note.rb │ ├── organization-field.rb │ ├── organization.rb │ ├── permission-set.rb │ ├── person-field.rb │ ├── person.rb │ ├── pipeline.rb │ ├── product-field.rb │ ├── product.rb │ ├── push-notification.rb │ ├── role.rb │ ├── search-result.rb │ ├── stage.rb │ ├── user-connection.rb │ ├── user-setting.rb │ └── user.rb ├── pipedrive-ruby.gemspec └── test ├── data ├── create_deal_body.json ├── create_note_body.json ├── create_organization_body.json └── create_person_body.json ├── helper.rb ├── test_pipedrive_authentication.rb ├── test_pipedrive_deal.rb ├── test_pipedrive_note.rb ├── test_pipedrive_organization.rb └── test_pipedrive_person.rb /.document: -------------------------------------------------------------------------------- 1 | lib/**/*.rb 2 | bin/* 3 | - 4 | features/**/*.feature 5 | LICENSE.txt 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # rcov generated 2 | coverage 3 | coverage.data 4 | 5 | /.ruby-* 6 | 7 | # rdoc generated 8 | rdoc 9 | 10 | # yard generated 11 | doc 12 | .yardoc 13 | 14 | # bundler 15 | .bundle 16 | 17 | # jeweler generated 18 | pkg 19 | 20 | # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore: 21 | # 22 | # * Create a file at ~/.gitignore 23 | # * Include files you want ignored 24 | # * Run: git config --global core.excludesfile ~/.gitignore 25 | # 26 | # After doing this, these files will be ignored in all your git projects, 27 | # saving you from having to 'pollute' every project you touch with them 28 | # 29 | # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line) 30 | # 31 | # For MacOS: 32 | # 33 | #.DS_Store 34 | 35 | # For TextMate 36 | #*.tmproj 37 | #tmtags 38 | 39 | # For emacs: 40 | #*~ 41 | #\#* 42 | #.\#* 43 | 44 | # For vim: 45 | #*.swp 46 | 47 | # For redcar: 48 | #.redcar 49 | 50 | # For rubinius: 51 | #*.rbc 52 | 53 | /.idea 54 | /.rvmrc 55 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | # Add dependencies required to use your gem here. 3 | # Example: 4 | # gem "activesupport", ">= 2.3.5" 5 | 6 | gem 'httparty' 7 | gem 'json', '>= 1.7.7' 8 | gem 'multi_xml', '>= 0.5.2' 9 | gem 'webmock' 10 | gem 'coveralls', :require => false 11 | 12 | # Add dependencies to develop your gem here. 13 | # Include everything needed to run rake, tests, features, etc. 14 | group :development do 15 | gem "shoulda", ">= 0" 16 | gem "rdoc", "~> 3.12" 17 | gem "bundler", ">= 1.0.0" 18 | gem "jeweler", ">= 1.8.4" 19 | gem "simplecov", ">= 0" 20 | end 21 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | activesupport (3.2.12) 5 | i18n (~> 0.6) 6 | multi_json (~> 1.0) 7 | addressable (2.3.4) 8 | bourne (1.1.2) 9 | mocha (= 0.10.5) 10 | colorize (0.5.8) 11 | coveralls (0.6.7) 12 | colorize 13 | multi_json (~> 1.3) 14 | rest-client 15 | simplecov (>= 0.7) 16 | thor 17 | crack (0.4.0) 18 | safe_yaml (~> 0.9.0) 19 | git (1.2.5) 20 | httparty (0.10.2) 21 | multi_json (~> 1.0) 22 | multi_xml (>= 0.5.2) 23 | i18n (0.6.4) 24 | jeweler (1.8.4) 25 | bundler (~> 1.0) 26 | git (>= 1.2.5) 27 | rake 28 | rdoc 29 | json (1.7.7) 30 | metaclass (0.0.1) 31 | mime-types (1.24) 32 | mocha (0.10.5) 33 | metaclass (~> 0.0.1) 34 | multi_json (1.6.1) 35 | multi_xml (0.5.3) 36 | rake (10.0.3) 37 | rdoc (3.12.2) 38 | json (~> 1.4) 39 | rest-client (1.6.7) 40 | mime-types (>= 1.16) 41 | safe_yaml (0.9.3) 42 | shoulda (3.3.2) 43 | shoulda-context (~> 1.0.1) 44 | shoulda-matchers (~> 1.4.1) 45 | shoulda-context (1.0.2) 46 | shoulda-matchers (1.4.2) 47 | activesupport (>= 3.0.0) 48 | bourne (~> 1.1.2) 49 | simplecov (0.7.1) 50 | multi_json (~> 1.0) 51 | simplecov-html (~> 0.7.1) 52 | simplecov-html (0.7.1) 53 | thor (0.18.1) 54 | webmock (1.11.0) 55 | addressable (>= 2.2.7) 56 | crack (>= 0.3.2) 57 | 58 | PLATFORMS 59 | ruby 60 | 61 | DEPENDENCIES 62 | bundler (>= 1.0.0) 63 | coveralls 64 | httparty 65 | jeweler (>= 1.8.4) 66 | json (>= 1.7.7) 67 | multi_xml (>= 0.5.2) 68 | rdoc (~> 3.12) 69 | shoulda 70 | simplecov 71 | webmock 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pipedrive-ruby 2 | 3 | [![Gem Version](https://badge.fury.io/rb/pipedrive-ruby.png)](http://badge.fury.io/rb/pipedrive-ruby) 4 | [![Code Climate](https://codeclimate.com/github/GeneralScripting/pipedrive-ruby.png)](https://codeclimate.com/github/GeneralScripting/pipedrive-ruby) 5 | [![Build Status](https://travis-ci.org/GeneralScripting/pipedrive-ruby.png?branch=master)](https://travis-ci.org/GeneralScripting/pipedrive-ruby) 6 | [![Coverage Status](https://coveralls.io/repos/GeneralScripting/pipedrive-ruby/badge.png?branch=master)](https://coveralls.io/r/GeneralScripting/pipedrive-ruby?branch=master) 7 | 8 | ## Installation 9 | 10 | gem install pipedrive-ruby 11 | 12 | ## Usage 13 | 14 | require 'pipedrive-ruby' 15 | Pipedrive.authenticate( YOUR_API_TOKEN ) 16 | Pipedrive::Deal.find( DEAL_ID ) 17 | 18 | ## API Calls 19 | Pipedrive::Deal.create( params ) 20 | Pipedrive::Deal.find( ) 21 | 22 | Pipedrive::Organization.create( params ) 23 | Pipedrive::Organization.find( ) 24 | 25 | Pipedrive::Person.create( params ) 26 | Pipedrive::Person.find( ) 27 | 28 | Pipedrive::Note.create( params ) 29 | 30 | You can check some of the calls at https://developers.pipedrive.com/v1 31 | 32 | 33 | ## Contributing to pipedrive-ruby 34 | 35 | * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet. 36 | * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it. 37 | * Fork the project. 38 | * Start a feature/bugfix branch. 39 | * Commit and push until you are happy with your contribution. 40 | * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally. 41 | * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it. 42 | 43 | ## License 44 | 45 | This gem is released under the [MIT License](http://www.opensource.org/licenses/MIT). 46 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'rubygems' 4 | require 'bundler' 5 | begin 6 | Bundler.setup(:default, :development) 7 | rescue Bundler::BundlerError => e 8 | $stderr.puts e.message 9 | $stderr.puts "Run `bundle install` to install missing gems" 10 | exit e.status_code 11 | end 12 | require 'rake' 13 | 14 | require 'jeweler' 15 | Jeweler::Tasks.new do |gem| 16 | # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options 17 | gem.name = "pipedrive-ruby" 18 | gem.homepage = "https://github.com/GeneralScripting/pipedrive-ruby.git" 19 | gem.license = "MIT" 20 | gem.summary = %Q{Ruby wrapper for the Pipedrive API} 21 | gem.description = %Q{Ruby wrapper for the Pipedrive API} 22 | gem.email = "jan@general-scripting.com" 23 | gem.authors = ["Jan Schwenzien", "Waldemar Kusnezow", "Joel Courtney"] 24 | # dependencies defined in Gemfile 25 | end 26 | Jeweler::RubygemsDotOrgTasks.new 27 | 28 | require 'rake/testtask' 29 | Rake::TestTask.new(:test) do |test| 30 | test.libs << 'lib' << 'test' 31 | test.pattern = 'test/**/test_*.rb' 32 | test.verbose = true 33 | end 34 | 35 | task :default => :test 36 | 37 | require 'rdoc/task' 38 | Rake::RDocTask.new do |rdoc| 39 | version = File.exist?('VERSION') ? File.read('VERSION') : "" 40 | 41 | rdoc.rdoc_dir = 'rdoc' 42 | rdoc.title = "pipedrive-rails #{version}" 43 | rdoc.rdoc_files.include('README*') 44 | rdoc.rdoc_files.include('lib/**/*.rb') 45 | end 46 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.3.3 -------------------------------------------------------------------------------- /lib/pipedrive-ruby.rb: -------------------------------------------------------------------------------- 1 | require 'pipedrive/base' 2 | require 'pipedrive/activity' 3 | require 'pipedrive/activity-type' 4 | require 'pipedrive/authorization' 5 | require 'pipedrive/currency' 6 | require 'pipedrive/deal' 7 | require 'pipedrive/deal-field' 8 | require 'pipedrive/file' 9 | require 'pipedrive/filter' 10 | require 'pipedrive/note' 11 | require 'pipedrive/organization' 12 | require 'pipedrive/person' 13 | require 'pipedrive/organization-field' 14 | require 'pipedrive/person-field' 15 | require 'pipedrive/permission-set' 16 | require 'pipedrive/pipeline' 17 | require 'pipedrive/product' 18 | require 'pipedrive/product-field' 19 | require 'pipedrive/role' 20 | require 'pipedrive/search-result' 21 | require 'pipedrive/stage' 22 | require 'pipedrive/user' 23 | require 'pipedrive/user-setting' 24 | require 'pipedrive/goal' 25 | require 'pipedrive/user-connection' 26 | require 'pipedrive/push-notification' 27 | 28 | module Pipedrive 29 | 30 | def self.authenticate(token) 31 | Base.authenticate(token) 32 | end 33 | 34 | end -------------------------------------------------------------------------------- /lib/pipedrive/activity-type.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class ActivityType < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/activity.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Activity < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/authorization.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Authorization < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/base.rb: -------------------------------------------------------------------------------- 1 | require 'httparty' 2 | require 'ostruct' 3 | require 'forwardable' 4 | 5 | module Pipedrive 6 | 7 | # Globally set request headers 8 | HEADERS = { 9 | "User-Agent" => "Ruby.Pipedrive.Api", 10 | "Accept" => "application/json", 11 | "Content-Type" => "application/x-www-form-urlencoded" 12 | } 13 | 14 | # Base class for setting HTTParty configurations globally 15 | class Base < OpenStruct 16 | 17 | include HTTParty 18 | 19 | base_uri 'api.pipedrive.com/v1' 20 | headers HEADERS 21 | format :json 22 | 23 | extend Forwardable 24 | def_delegators 'self.class', :delete, :get, :post, :put, :resource_path, :bad_response 25 | 26 | attr_reader :data 27 | 28 | # Create a new Pipedrive::Base object. 29 | # 30 | # Only used internally 31 | # 32 | # @param [Hash] attributes 33 | # @return [Pipedrive::Base] 34 | def initialize(attrs = {}) 35 | if attrs['data'] 36 | struct_attrs = attrs['data'] 37 | 38 | if attrs['additional_data'] 39 | struct_attrs.merge!(attrs['additional_data']) 40 | end 41 | else 42 | struct_attrs = attrs 43 | end 44 | 45 | super(struct_attrs) 46 | end 47 | 48 | # Updates the object. 49 | # 50 | # @param [Hash] opts 51 | # @return [Boolean] 52 | def update(opts = {}) 53 | res = put "#{resource_path}/#{id}", :body => opts 54 | if res.success? 55 | res['data'] = Hash[res['data'].map {|k, v| [k.to_sym, v] }] 56 | @table.merge!(res['data']) 57 | else 58 | false 59 | end 60 | end 61 | 62 | class << self 63 | # Sets the authentication credentials in a class variable. 64 | # 65 | # @param [String] email cl.ly email 66 | # @param [String] password cl.ly password 67 | # @return [Hash] authentication credentials 68 | def authenticate(token) 69 | default_params :api_token => token 70 | end 71 | 72 | # Examines a bad response and raises an appropriate exception 73 | # 74 | # @param [HTTParty::Response] response 75 | def bad_response(response, params={}) 76 | puts params.inspect 77 | if response.class == HTTParty::Response 78 | raise HTTParty::ResponseError, response 79 | end 80 | raise StandardError, 'Unknown error' 81 | end 82 | 83 | def new_list( attrs ) 84 | attrs['data'].is_a?(Array) ? attrs['data'].map {|data| self.new( 'data' => data ) } : [] 85 | end 86 | 87 | def all(response = nil, options={},get_absolutely_all=false) 88 | res = response || get(resource_path, options) 89 | if res.ok? 90 | data = res['data'].nil? ? [] : res['data'].map{|obj| new(obj)} 91 | if get_absolutely_all && res['additional_data']['pagination'] && res['additional_data']['pagination'] && res['additional_data']['pagination']['more_items_in_collection'] 92 | options[:query] = options[:query].merge({:start => res['additional_data']['pagination']['next_start']}) 93 | data += self.all(nil,options,true) 94 | end 95 | data 96 | else 97 | bad_response(res,attrs) 98 | end 99 | end 100 | 101 | def create( opts = {} ) 102 | res = post resource_path, :body => opts 103 | if res.success? 104 | res['data'] = opts.merge res['data'] 105 | new(res) 106 | else 107 | bad_response(res,opts) 108 | end 109 | end 110 | 111 | def find(id) 112 | res = get "#{resource_path}/#{id}" 113 | res.ok? ? new(res) : bad_response(res,id) 114 | end 115 | 116 | def find_by_name(name, opts={}) 117 | res = get "#{resource_path}/find", :query => { :term => name }.merge(opts) 118 | res.ok? ? new_list(res) : bad_response(res,{:name => name}.merge(opts)) 119 | end 120 | 121 | def resource_path 122 | # The resource path should match the camelCased class name with the 123 | # first letter downcased. Pipedrive API is sensitive to capitalisation 124 | klass = name.split('::').last 125 | klass[0] = klass[0].chr.downcase 126 | klass.end_with?('y') ? "/#{klass.chop}ies" : "/#{klass}s" 127 | end 128 | end 129 | end 130 | 131 | end 132 | -------------------------------------------------------------------------------- /lib/pipedrive/currency.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Currency < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/deal-field.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class DealField < Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /lib/pipedrive/deal.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Deal < Base 3 | 4 | def add_product(opts = {}) 5 | res = post "#{resource_path}/#{id}/products", :body => opts 6 | res.success? ? res['data']['product_attachment_id'] : bad_response(res,opts) 7 | end 8 | 9 | def products 10 | Product.all(get "#{resource_path}/#{id}/products") 11 | end 12 | 13 | def remove_product product_attachment_id 14 | res = delete "#{resource_path}/#{id}/products", { :body => { :product_attachment_id => product_attachment_id } } 15 | res.success? ? nil : bad_response(res,product_attachment_id) 16 | end 17 | 18 | def activities 19 | Activity.all(get "#{resource_path}/#{id}/activities") 20 | end 21 | 22 | def files 23 | File.all(get "#{resource_path}/#{id}/files") 24 | end 25 | 26 | def notes(opts = {:sort_by => 'add_time', :sort_mode => 'desc'}) 27 | Note.all( get("/notes", :query => opts.merge(:deal_id => id) ) ) 28 | end 29 | 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/pipedrive/file.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class File < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/filter.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Filter < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/goal.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Goal < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/note.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Note < Base 3 | 4 | class << self 5 | 6 | end 7 | end 8 | end -------------------------------------------------------------------------------- /lib/pipedrive/organization-field.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class OrganizationField < Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /lib/pipedrive/organization.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Organization < Base 3 | 4 | def persons 5 | Person.all(get "#{resource_path}/#{id}/persons") 6 | end 7 | 8 | def deals 9 | Deal.all(get "#{resource_path}/#{id}/deals") 10 | end 11 | 12 | class << self 13 | 14 | def find_or_create_by_name(name, opts={}) 15 | find_by_name(name).first || create(opts.merge(:name => name)) 16 | end 17 | 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/pipedrive/permission-set.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class PermissionSet < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/person-field.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class PersonField < Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /lib/pipedrive/person.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Person < Base 3 | 4 | class << self 5 | 6 | def find_or_create_by_name(name, opts={}) 7 | find_by_name(name, :org_id => opts[:org_id]).first || create(opts.merge(:name => name)) 8 | end 9 | 10 | end 11 | 12 | def deals() 13 | Deal.all(get "#{resource_path}/#{id}/deals", :everyone => 1) 14 | end 15 | end 16 | end -------------------------------------------------------------------------------- /lib/pipedrive/pipeline.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Pipeline < Base 3 | def stages 4 | Stage.all(get "/stages", { :pipeline_id => self.id }) 5 | end 6 | 7 | def statistics(id, start_date, end_date) 8 | res = get("#{resource_path}/#{id}/movement_statistics", 9 | :query => {:start_date => start_date, :end_date => end_date}) 10 | res.ok? ? new(res) : bad_response(res,{:id=>id,:start_date=>start_date,:end_date=>end_date}) 11 | end 12 | 13 | def deals(id, stage_id) 14 | Pipedrive::Deal.all(get "#{resource_path}/#{id}/deals", :stage_id => stage_id ) 15 | end 16 | end 17 | end -------------------------------------------------------------------------------- /lib/pipedrive/product-field.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class ProductField < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/product.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Product < Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /lib/pipedrive/push-notification.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class PushNotification < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/role.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Role < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/search-result.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class SearchResult < Base 3 | 4 | # Class Methods 5 | class << self 6 | 7 | def search(term, start=0, limit=nil) 8 | res = get(resource_path, :query => { :term => term, :start => start, :limit => limit}) 9 | if res.ok? 10 | res['data'].nil? ? [] : res['data'].map{|obj| new(obj)} 11 | else 12 | bad_response(res,{:term=>term,:start=>start,:limit=>limit}) 13 | end 14 | end 15 | 16 | def field(term, field_type, field_key, opts={}) 17 | res = get("#{resource_path}/field", :query => opts.merge(:term => term, :field_type => field_type, :field_key => field_key) ) 18 | if res.ok? 19 | res['data'].nil? ? [] : res['data'].map{|obj| new(obj)} 20 | else 21 | bad_response(res,{:term=>term,:field_type=>field_type,:field_key=>field_key}.merge(opts)) 22 | end 23 | end 24 | 25 | end 26 | 27 | end 28 | end -------------------------------------------------------------------------------- /lib/pipedrive/stage.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class Stage < Base 3 | def self.deals(id) 4 | Deal.all(get "#{resource_path}/#{id}/deals", :query => {:everyone => 1}) 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/pipedrive/user-connection.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class UserConnection < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/user-setting.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class UserSetting < Base 3 | end 4 | end -------------------------------------------------------------------------------- /lib/pipedrive/user.rb: -------------------------------------------------------------------------------- 1 | module Pipedrive 2 | class User < Base 3 | end 4 | end -------------------------------------------------------------------------------- /pipedrive-ruby.gemspec: -------------------------------------------------------------------------------- 1 | # Generated by jeweler 2 | # DO NOT EDIT THIS FILE DIRECTLY 3 | # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' 4 | # -*- encoding: utf-8 -*- 5 | 6 | Gem::Specification.new do |s| 7 | s.name = "pipedrive-ruby" 8 | s.version = "0.3.3" 9 | 10 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= 11 | s.authors = ["Jan Schwenzien", "Waldemar Kusnezow", "Joel Courtney"] 12 | s.date = "2014-04-23" 13 | s.description = "Ruby wrapper for the Pipedrive API" 14 | s.email = "jan@general-scripting.com" 15 | s.extra_rdoc_files = [ 16 | "README.md" 17 | ] 18 | s.files = [ 19 | ".document", 20 | "Gemfile", 21 | "Gemfile.lock", 22 | "README.md", 23 | "Rakefile", 24 | "VERSION", 25 | "lib/pipedrive-ruby.rb", 26 | "lib/pipedrive/activity-type.rb", 27 | "lib/pipedrive/activity.rb", 28 | "lib/pipedrive/authorization.rb", 29 | "lib/pipedrive/base.rb", 30 | "lib/pipedrive/currency.rb", 31 | "lib/pipedrive/deal-field.rb", 32 | "lib/pipedrive/deal.rb", 33 | "lib/pipedrive/file.rb", 34 | "lib/pipedrive/filter.rb", 35 | "lib/pipedrive/goal.rb", 36 | "lib/pipedrive/note.rb", 37 | "lib/pipedrive/organization-field.rb", 38 | "lib/pipedrive/organization.rb", 39 | "lib/pipedrive/permission-set.rb", 40 | "lib/pipedrive/person-field.rb", 41 | "lib/pipedrive/person.rb", 42 | "lib/pipedrive/pipeline.rb", 43 | "lib/pipedrive/product-field.rb", 44 | "lib/pipedrive/product.rb", 45 | "lib/pipedrive/push-notification.rb", 46 | "lib/pipedrive/role.rb", 47 | "lib/pipedrive/search-result.rb", 48 | "lib/pipedrive/stage.rb", 49 | "lib/pipedrive/user-connection.rb", 50 | "lib/pipedrive/user-setting.rb", 51 | "lib/pipedrive/user.rb", 52 | "pipedrive-ruby.gemspec", 53 | "test/data/create_deal_body.json", 54 | "test/data/create_note_body.json", 55 | "test/data/create_organization_body.json", 56 | "test/data/create_person_body.json", 57 | "test/helper.rb", 58 | "test/test_pipedrive_authentication.rb", 59 | "test/test_pipedrive_deal.rb", 60 | "test/test_pipedrive_note.rb", 61 | "test/test_pipedrive_organization.rb", 62 | "test/test_pipedrive_person.rb" 63 | ] 64 | s.homepage = "https://github.com/GeneralScripting/pipedrive-ruby.git" 65 | s.licenses = ["MIT"] 66 | s.require_paths = ["lib"] 67 | s.rubygems_version = "1.8.25" 68 | s.summary = "Ruby wrapper for the Pipedrive API" 69 | 70 | if s.respond_to? :specification_version then 71 | s.specification_version = 3 72 | 73 | if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then 74 | s.add_runtime_dependency(%q, [">= 0"]) 75 | s.add_runtime_dependency(%q, [">= 1.7.7"]) 76 | s.add_runtime_dependency(%q, [">= 0.5.2"]) 77 | s.add_runtime_dependency(%q, [">= 0"]) 78 | s.add_runtime_dependency(%q, [">= 0"]) 79 | s.add_development_dependency(%q, [">= 0"]) 80 | s.add_development_dependency(%q, ["~> 3.12"]) 81 | s.add_development_dependency(%q, [">= 1.0.0"]) 82 | s.add_development_dependency(%q, [">= 1.8.4"]) 83 | s.add_development_dependency(%q, [">= 0"]) 84 | else 85 | s.add_dependency(%q, [">= 0"]) 86 | s.add_dependency(%q, [">= 1.7.7"]) 87 | s.add_dependency(%q, [">= 0.5.2"]) 88 | s.add_dependency(%q, [">= 0"]) 89 | s.add_dependency(%q, [">= 0"]) 90 | s.add_dependency(%q, [">= 0"]) 91 | s.add_dependency(%q, ["~> 3.12"]) 92 | s.add_dependency(%q, [">= 1.0.0"]) 93 | s.add_dependency(%q, [">= 1.8.4"]) 94 | s.add_dependency(%q, [">= 0"]) 95 | end 96 | else 97 | s.add_dependency(%q, [">= 0"]) 98 | s.add_dependency(%q, [">= 1.7.7"]) 99 | s.add_dependency(%q, [">= 0.5.2"]) 100 | s.add_dependency(%q, [">= 0"]) 101 | s.add_dependency(%q, [">= 0"]) 102 | s.add_dependency(%q, [">= 0"]) 103 | s.add_dependency(%q, ["~> 3.12"]) 104 | s.add_dependency(%q, [">= 1.0.0"]) 105 | s.add_dependency(%q, [">= 1.8.4"]) 106 | s.add_dependency(%q, [">= 0"]) 107 | end 108 | end 109 | 110 | -------------------------------------------------------------------------------- /test/data/create_deal_body.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": { 4 | "id": 337, 5 | "user_id": 96701, 6 | "person_id": null, 7 | "org_id": 72312, 8 | "stage_id": 30, 9 | "title": "Dope Deal", 10 | "value": 37, 11 | "currency": "EUR", 12 | "add_time": "2013-03-01 14:01:03", 13 | "update_time": "2013-03-01 14:01:03", 14 | "stage_change_time": "2013-03-01 14:01:03", 15 | "active": true, 16 | "deleted": false, 17 | "status": "open", 18 | "next_activity_date": null, 19 | "next_activity_time": null, 20 | "next_activity_id": null, 21 | "last_activity_id": null, 22 | "last_activity_date": null, 23 | "lost_reason": null, 24 | "visible_to": "0", 25 | "close_time": null, 26 | "pipeline_id": 1, 27 | "won_time": null, 28 | "lost_time": null, 29 | "products_count": null, 30 | "files_count": null, 31 | "activities_count": null, 32 | "undone_activities_count": null, 33 | "person_name": null, 34 | "org_name": null, 35 | "stage_order_nr": 21, 36 | "weighted_value": 37, 37 | "formatted_weighted_value": "37 €", 38 | "formatted_value": "37 €" 39 | } 40 | } -------------------------------------------------------------------------------- /test/data/create_note_body.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": { 4 | "id": 11, 5 | "user_id": 131904, 6 | "deal_id": null, 7 | "person_id": 1, 8 | "org_id": null, 9 | "content": "abc", 10 | "add_time": "2013-08-19 01:23:03", 11 | "update_time": "", 12 | "active_flag": true, 13 | "organization": null, 14 | "person": { 15 | "name": "testando" 16 | }, 17 | "deal": null, 18 | "user": { 19 | "email": "brunogh@gmail.com", 20 | "name": "Bruno", 21 | "icon_url": "https://pipedrive-us-usericons.s3.amazonaws.com/profile_120x120_131904.jpg", 22 | "is_you": true 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /test/data/create_organization_body.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": { 4 | "id": 7553, 5 | "company_id": 72312, 6 | "owner_id": 96701, 7 | "name": "Dope.org", 8 | "open_deals_count": 0, 9 | "closed_deals_count": null, 10 | "people_count": 0, 11 | "activities_count": null, 12 | "undone_activities_count": null, 13 | "files_count": null, 14 | "active_flag": true, 15 | "category_id": null, 16 | "country_code": null, 17 | "temp_old_id": null, 18 | "first_char": "d", 19 | "permission_group_id": null, 20 | "update_time": null, 21 | "add_time": "2013-03-01 13:46:06", 22 | "visible_to": "1", 23 | "next_activity_date": null, 24 | "next_activity_time": null, 25 | "next_activity_id": null, 26 | "last_activity_id": null, 27 | "last_activity_date": null, 28 | "edit_name": true 29 | } 30 | } -------------------------------------------------------------------------------- /test/data/create_person_body.json: -------------------------------------------------------------------------------- 1 | { 2 | "success": true, 3 | "data": { 4 | "id": 3826, 5 | "company_id": 72312, 6 | "owner_id": null, 7 | "org_id": 404, 8 | "name": "John Dope", 9 | "first_name": null, 10 | "last_name": null, 11 | "open_deals_count": 0, 12 | "closed_deals_count": null, 13 | "activities_count": null, 14 | "undone_activities_count": null, 15 | "files_count": null, 16 | "active_flag": true, 17 | "phone": [ 18 | { 19 | "label": "", 20 | "value": "0123456789", 21 | "primary": true 22 | } 23 | ], 24 | "email": [ 25 | { 26 | "label": "", 27 | "value": "john@dope.org", 28 | "primary": true 29 | } 30 | ], 31 | "first_char": "j", 32 | "update_time": null, 33 | "add_time": "2013-03-01 13:34:23", 34 | "visible_to": "1", 35 | "next_activity_date": null, 36 | "next_activity_time": null, 37 | "next_activity_id": null, 38 | "last_activity_id": null, 39 | "last_activity_date": null, 40 | "org_name": null, 41 | "owner_name": "Unnamed", 42 | "im": [ 43 | { 44 | "value": "", 45 | "primary": true 46 | } 47 | ] 48 | } 49 | } -------------------------------------------------------------------------------- /test/helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | 4 | require 'coveralls' 5 | Coveralls.wear! 6 | 7 | begin 8 | Bundler.setup(:default, :development) 9 | rescue Bundler::BundlerError => e 10 | $stderr.puts e.message 11 | $stderr.puts "Run `bundle install` to install missing gems" 12 | exit e.status_code 13 | end 14 | require 'test/unit' 15 | require 'shoulda' 16 | # require 'mocha/setup' 17 | require 'webmock/test_unit' 18 | 19 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) 20 | $LOAD_PATH.unshift(File.dirname(__FILE__)) 21 | require 'pipedrive-ruby' 22 | 23 | class Test::Unit::TestCase 24 | end 25 | -------------------------------------------------------------------------------- /test/test_pipedrive_authentication.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | class TestPipedriveAuthentication < Test::Unit::TestCase 4 | should "set authentication credentials on Pipedrive::Base" do 5 | Pipedrive.authenticate("some-token") 6 | assert_equal "some-token", Pipedrive::Base.default_options[:default_params][:api_token] 7 | end 8 | 9 | should "send authentication token with each request" do 10 | Pipedrive.authenticate("some-token") 11 | 12 | stub_request(:get, "http://api.pipedrive.com/v1/?api_token=some-token"). 13 | with(:headers => { 14 | 'Accept'=>'application/json', 15 | 'Content-Type'=>'application/x-www-form-urlencoded', 16 | 'User-Agent'=>'Ruby.Pipedrive.Api' 17 | }). 18 | to_return(:status => 200, :body => "", :headers => {}) 19 | Pipedrive::Base.get("/") 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /test/test_pipedrive_deal.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | class TestPipedriveDeal < Test::Unit::TestCase 4 | def setup 5 | Pipedrive.authenticate("some-token") 6 | end 7 | 8 | should "execute a valid person request" do 9 | body = { 10 | "currency" => "EUR", 11 | "org_id" => "72312", 12 | "title" => "Dope Deal", 13 | "value" => "37k" 14 | } 15 | 16 | stub_request(:post, "http://api.pipedrive.com/v1/deals?api_token=some-token"). 17 | with(:body => body, 18 | :headers => { 19 | 'Accept'=>'application/json', 20 | 'Content-Type'=>'application/x-www-form-urlencoded', 21 | 'User-Agent'=>'Ruby.Pipedrive.Api' 22 | }). 23 | to_return( 24 | :status => 200, 25 | :body => File.read(File.join(File.dirname(__FILE__), "data", "create_deal_body.json")), 26 | :headers => { 27 | "server" => "nginx/1.2.4", 28 | "date" => "Fri, 01 Mar 2013 14:01:03 GMT", 29 | "content-type" => "application/json", 30 | "content-length" => "1260", 31 | "connection" => "keep-alive", 32 | "access-control-allow-origin" => "*" 33 | } 34 | ) 35 | 36 | deal = ::Pipedrive::Deal.create(body) 37 | 38 | assert_equal "Dope Deal", deal.title 39 | assert_equal 37, deal.value 40 | assert_equal "EUR", deal.currency 41 | assert_equal 72312, deal.org_id 42 | end 43 | 44 | should "return bad_response on errors" do 45 | #TODO 46 | # flunk "to be tested" 47 | end 48 | end -------------------------------------------------------------------------------- /test/test_pipedrive_note.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | class TestPipedriveNote < Test::Unit::TestCase 4 | def setup 5 | Pipedrive.authenticate("some-token") 6 | end 7 | 8 | should "execute a valid person request" do 9 | body = { 10 | "content"=>"whatever html body", 11 | "person_id"=>"1" 12 | # org_id 13 | # deal_id 14 | } 15 | 16 | stub_request(:post, "http://api.pipedrive.com/v1/notes?api_token=some-token"). 17 | with(:body => body, :headers => { 18 | 'Accept'=>'application/json', 19 | 'Content-Type'=>'application/x-www-form-urlencoded', 20 | 'User-Agent'=>'Ruby.Pipedrive.Api' 21 | }). 22 | to_return( 23 | :status => 200, 24 | :body => File.read(File.join(File.dirname(__FILE__), "data", "create_note_body.json")), 25 | :headers => { 26 | "server" => "nginx/1.2.4", 27 | "date" => "Fri, 01 Mar 2013 13:34:23 GMT", 28 | "content-type" => "application/json", 29 | "content-length" => "1164", 30 | "connection" => "keep-alive", 31 | "access-control-allow-origin" => "*" 32 | } 33 | ) 34 | 35 | note = ::Pipedrive::Note.create(body) 36 | 37 | assert_equal "abc", note.content 38 | assert_equal 1, note.person_id 39 | end 40 | 41 | should "return bad_response on errors" do 42 | #TODO 43 | # flunk "to be tested" 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /test/test_pipedrive_organization.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | class TestPipedriveOrganization < Test::Unit::TestCase 4 | def setup 5 | Pipedrive.authenticate("some-token") 6 | end 7 | 8 | should "execute a valid person request" do 9 | stub_request(:post, "http://api.pipedrive.com/v1/organizations?api_token=some-token"). 10 | with(:body => { 11 | "name" => "Dope.org" 12 | }, 13 | :headers => { 14 | 'Accept'=>'application/json', 15 | 'Content-Type'=>'application/x-www-form-urlencoded', 16 | 'User-Agent'=>'Ruby.Pipedrive.Api' 17 | }). 18 | to_return( 19 | :status => 200, 20 | :body => File.read(File.join(File.dirname(__FILE__), "data", "create_organization_body.json")), 21 | :headers => { 22 | "server" => "nginx/1.2.4", 23 | "date" => "Fri, 01 Mar 2013 13:46:06 GMT", 24 | "content-type" => "application/json", 25 | "content-length" => "3337", 26 | "connection" => "keep-alive", 27 | "access-control-allow-origin" => "*" 28 | } 29 | ) 30 | 31 | organization = ::Pipedrive::Organization.create({ 32 | name: "Dope.org" 33 | }) 34 | 35 | assert_equal "Dope.org", organization.name 36 | end 37 | 38 | should "return bad_response on errors" do 39 | # TODO 40 | # flunk "to be tested" 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /test/test_pipedrive_person.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | class TestPipedrivePerson < Test::Unit::TestCase 4 | def setup 5 | Pipedrive.authenticate("some-token") 6 | end 7 | 8 | should "execute a valid person request" do 9 | body = { 10 | "email"=>["john@dope.org"], 11 | "name"=>"John Dope", 12 | "org_id"=>"404", 13 | "phone"=>["0123456789"] 14 | } 15 | 16 | stub_request(:post, "http://api.pipedrive.com/v1/persons?api_token=some-token"). 17 | with(:body => body, :headers => { 18 | 'Accept'=>'application/json', 19 | 'Content-Type'=>'application/x-www-form-urlencoded', 20 | 'User-Agent'=>'Ruby.Pipedrive.Api' 21 | }). 22 | to_return( 23 | :status => 200, 24 | :body => File.read(File.join(File.dirname(__FILE__), "data", "create_person_body.json")), 25 | :headers => { 26 | "server" => "nginx/1.2.4", 27 | "date" => "Fri, 01 Mar 2013 13:34:23 GMT", 28 | "content-type" => "application/json", 29 | "content-length" => "1164", 30 | "connection" => "keep-alive", 31 | "access-control-allow-origin" => "*" 32 | } 33 | ) 34 | 35 | person = ::Pipedrive::Person.create(body) 36 | 37 | assert_equal "John Dope", person.name 38 | assert_equal 404, person.org_id 39 | assert_equal "john@dope.org", person.email.first.fetch("value") 40 | assert_equal "0123456789", person.phone.first.fetch("value") 41 | end 42 | 43 | should "return bad_response on errors" do 44 | #TODO 45 | # flunk "to be tested" 46 | end 47 | end 48 | --------------------------------------------------------------------------------