civicrm 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ /pkg
2
+ .rvmrc
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
@@ -0,0 +1 @@
1
+ Iskander Haziev <gvalmon@gmail.com>
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
@@ -0,0 +1,47 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ civicrm (1.0.1)
5
+ activemodel
6
+ activesupport
7
+ nokogiri
8
+ rest-client (~> 1.4)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activemodel (3.2.13)
14
+ activesupport (= 3.2.13)
15
+ builder (~> 3.0.0)
16
+ activesupport (3.2.13)
17
+ i18n (= 0.6.1)
18
+ multi_json (~> 1.0)
19
+ builder (3.0.4)
20
+ diff-lcs (1.2.1)
21
+ i18n (0.6.1)
22
+ metaclass (0.0.1)
23
+ mime-types (1.22)
24
+ mocha (0.10.5)
25
+ metaclass (~> 0.0.1)
26
+ multi_json (1.7.2)
27
+ nokogiri (1.5.9)
28
+ rake (10.0.3)
29
+ rest-client (1.6.7)
30
+ mime-types (>= 1.16)
31
+ rspec (2.13.0)
32
+ rspec-core (~> 2.13.0)
33
+ rspec-expectations (~> 2.13.0)
34
+ rspec-mocks (~> 2.13.0)
35
+ rspec-core (2.13.1)
36
+ rspec-expectations (2.13.0)
37
+ diff-lcs (>= 1.1.3, < 2.0)
38
+ rspec-mocks (2.13.0)
39
+
40
+ PLATFORMS
41
+ ruby
42
+
43
+ DEPENDENCIES
44
+ civicrm!
45
+ mocha
46
+ rake
47
+ rspec
@@ -0,0 +1,11 @@
1
+ === 1.0 2013-04-8
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
5
+
6
+ === 1.1 2013-05-8
7
+
8
+ * 3 minor enhancements:
9
+ * Fix gem specs
10
+ * added CiviCrm::XML.encode method
11
+ * CiviCrm::Client.request not accepts only 2 params, "path" option is removed
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2013 CiviCrm.com. (https://civicrm.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ ## Installation
2
+
3
+ * $ gem install civicrm
4
+
5
+ ## Getting started
6
+
7
+ ```ruby
8
+ * CiviCrm.site_key = 'YOUR_SITE_KEY'
9
+ * // More info about site_key:
10
+ * // http://wiki.civicrm.org/confluence/display/CRMDOC43/Managing+Scheduled+Jobs
11
+ * CiviCrm.api_base = 'https://www.example.org/path/to/civi/codebase/'
12
+ * CiviCrm.authenticate('demo', 'demo')
13
+ ```
14
+
15
+ ## CiviCrm Objects
16
+
17
+ ```ruby
18
+ * CiviCrm::Contact.all # get list of contacts
19
+ * CiviCrm::Contact.create(contact_type: 'Organization', organization_name: 'test') # create contact
20
+ * CiviCrm::Contact.find(1).delete # find and delete
21
+ ```
22
+
23
+ ## Testing
24
+ ```
25
+ rspec spec
26
+ ```
27
+
28
+ ## Useful links
29
+
30
+ * http://wiki.civicrm.org/confluence/display/CRMDOC43/REST+interface
31
+ * http://drupal.demo.civicrm.org/civicrm/api/explorer
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake'
5
+ require 'rspec/core/rake_task'
6
+
7
+ desc "Run all examples"
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ t.rspec_opts = %w[--color]
10
+ end
11
+
12
+ task :default => [:spec]
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
3
+
4
+ libs = " -r irb/completion"
5
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/civicrm'}"
6
+ puts "Loading CiviCrm gem"
7
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,29 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
2
+
3
+ require 'civicrm/version'
4
+
5
+ spec = Gem::Specification.new do |s|
6
+ s.name = 'civicrm'
7
+ s.version = CiviCrm::VERSION
8
+ s.summary = 'Ruby bindings for the CiviCRM API'
9
+ s.description = 'See http://civicrm.org for details.'
10
+ s.authors = ['Iskander Haziev']
11
+ s.email = ['gvalmon@gmail.com']
12
+ s.homepage = 'http://civicrm.org'
13
+ s.executables = 'civicrm'
14
+ s.require_paths = %w{lib}
15
+
16
+ s.add_dependency('rest-client', '~> 1.4')
17
+ s.add_dependency('activesupport')
18
+ s.add_dependency('activemodel')
19
+ s.add_dependency('nokogiri')
20
+
21
+ s.add_development_dependency('rake')
22
+ s.add_development_dependency('rspec')
23
+ s.add_development_dependency('mocha')
24
+
25
+ s.files = `git ls-files`.split("\n")
26
+ s.test_files = `git ls-files -- test/*`.split("\n")
27
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
28
+ s.require_paths = ['lib']
29
+ end
@@ -0,0 +1,47 @@
1
+ require 'active_support/deprecation'
2
+ require 'active_support/core_ext/module'
3
+ require 'active_support/core_ext/hash'
4
+ require 'active_support/inflector'
5
+ require 'rest-client'
6
+ require 'nokogiri'
7
+
8
+ # utils
9
+ require 'civicrm/client'
10
+ require 'civicrm/xml'
11
+ require 'civicrm/resource'
12
+ require 'civicrm/version'
13
+
14
+ # actions
15
+ require 'civicrm/actions/list'
16
+ require 'civicrm/actions/create'
17
+ require 'civicrm/actions/update'
18
+ require 'civicrm/actions/destroy'
19
+ require 'civicrm/actions/find'
20
+
21
+ # exceptions
22
+ require 'civicrm/errors'
23
+
24
+ # resources
25
+ require 'civicrm/resources/base'
26
+
27
+ module CiviCrm
28
+ @@api_key = nil
29
+ @@site_key = nil
30
+ @@api_base = 'https://www.example.org/path/to/civi/codebase'
31
+ @@api_version = 'v3'
32
+ @@user_authenticated = false
33
+
34
+ mattr_accessor :api_key, :api_base, :api_version, :site_key
35
+
36
+ def self.api_url(path = '')
37
+ base = "#{api_base}/civicrm/extern/rest.php?#{path}"
38
+ base += "&api_key=#{@@api_key}" if @@api_key
39
+ base += "&key=#{@@site_key}" if @@site_key
40
+ base
41
+ end
42
+
43
+ def self.authenticate(name, password)
44
+ auth = Client.request(:post, q: 'civicrm/login', name: name, pass: password)
45
+ @@api_key = auth[0]['api_key']
46
+ end
47
+ end
@@ -0,0 +1,17 @@
1
+ module CiviCrm
2
+ module Actions
3
+ module Create
4
+ module ClassMethods
5
+ def create(attrs = {})
6
+ params = {'entity' => entity_class_name, 'action' => 'create'}
7
+ response = CiviCrm::Client.request(:post, params.merge(attrs))
8
+ Resource.build_from(response.first, params)
9
+ end
10
+ end
11
+
12
+ def self.included(base)
13
+ base.extend(ClassMethods)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module CiviCrm
2
+ module Actions
3
+ module Destroy
4
+ def delete
5
+ params = {'entity' => self.class.entity_class_name, 'action' => 'delete', 'id' => id}
6
+ response = CiviCrm::Client.request(:post, params)
7
+ refresh_from(response.first.to_hash)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module CiviCrm
2
+ module Actions
3
+ module Find
4
+ module ClassMethods
5
+ def find(id)
6
+ params = {'entity' => entity_class_name, 'action' => 'getsingle', 'id' => id}
7
+ response = CiviCrm::Client.request(:get, params)
8
+ Resource.build_from(response.first, params)
9
+ end
10
+ end
11
+
12
+ def self.included(base)
13
+ base.extend(ClassMethods)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,29 @@
1
+ module CiviCrm
2
+ module Actions
3
+ module List
4
+ module ClassMethods
5
+ def all(params = {})
6
+ params.merge!('entity' => entity_class_name, 'action' => 'get')
7
+ response = CiviCrm::Client.request(:get, params)
8
+ Resource.build_from(response, params)
9
+ end
10
+
11
+ def count
12
+ all.count
13
+ end
14
+
15
+ def first
16
+ all.first
17
+ end
18
+
19
+ def last
20
+ all.last
21
+ end
22
+ end
23
+
24
+ def self.included(base)
25
+ base.extend(ClassMethods)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ module CiviCrm
2
+ module Actions
3
+ module Update
4
+ # TODO: this method doesn't work yet
5
+ def update(attrs = {})
6
+ params = {'entity' => self.class.entity_class_name, 'action' => 'replace', 'id' => id}
7
+ new_attrs = attributes.merge(attrs)
8
+ response = CiviCrm::Client.request(:post, params.merge(values: new_attrs))
9
+ refresh_from(response.first.to_hash)
10
+ end
11
+
12
+ def save
13
+ @previously_changed = changes
14
+ @changed_attributes.clear
15
+ update()
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,70 @@
1
+ module CiviCrm
2
+ class Client
3
+ class << self
4
+
5
+ # Returns parsed class inherited from CiviCrm::Resource
6
+ def request(method, params = {})
7
+ unless CiviCrm.site_key
8
+ raise CiviCrm::Errors::Unauthorized, "Please specify CiviCrm.site_key"
9
+ end
10
+ headers = {
11
+ :user_agent => "CiviCrm RubyClient/#{CiviCrm::VERSION}"
12
+ }
13
+
14
+ opts = {
15
+ :method => method,
16
+ :timeout => 80,
17
+ :headers => headers
18
+ }
19
+
20
+ # build params
21
+ case method.to_s.downcase.to_sym
22
+ when :get, :head, :delete
23
+ path = params.count > 0 ? stringify_params(params) : ''
24
+ else
25
+ opts[:payload] = stringify_params(params)
26
+ end
27
+ opts[:url] = CiviCrm.api_url(path)
28
+ response = execute(opts)
29
+ body, code = response.body, response.code
30
+ CiviCrm::XML.parse(body)
31
+ end
32
+
33
+ def execute(opts)
34
+ RestClient::Request.execute(opts)
35
+ rescue RuntimeError => e
36
+ case e.http_code.to_i
37
+ when 400
38
+ raise CiviCrm::Errors::BadRequest, e.http_body
39
+ when 401
40
+ raise CiviCrm::Errors::Unauthorized, e.http_body
41
+ when 403
42
+ raise CiviCrm::Errors::Forbidden, e.http_body
43
+ when 404
44
+ raise CiviCrm::Errors::NotFound, e.http_body
45
+ when 500
46
+ raise CiviCrm::Errors::InternalError, e.http_body
47
+ else
48
+ raise e
49
+ end
50
+ end
51
+
52
+ def uri_escape(key)
53
+ URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
54
+ end
55
+
56
+ def flatten_params(params, parent_key = nil)
57
+ result = []
58
+ params.each do |key, value|
59
+ flatten_key = parent_key ? "#{parent_key}[#{uri_escape(key)}]" : uri_escape(key)
60
+ result += value.is_a?(Hash) ? flatten_params(value, flatten_key) : [[flatten_key, value]]
61
+ end
62
+ result
63
+ end
64
+
65
+ def stringify_params(params)
66
+ flatten_params(params).collect{|key, value| "#{key}=#{uri_escape(value)}"}.join('&')
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,9 @@
1
+ module CiviCrm
2
+ module Errors
3
+ class Unauthorized < Exception; end;
4
+ class InternalError < Exception; end;
5
+ class Forbidden < Exception; end;
6
+ class BadRequest < Exception; end;
7
+ class NotFound < Exception; end;
8
+ end
9
+ end
@@ -0,0 +1,84 @@
1
+ require 'active_model/dirty'
2
+ module CiviCrm
3
+ class Resource
4
+ include ActiveModel::Dirty
5
+ class_attribute :entity_name
6
+
7
+ def initialize(values = {})
8
+ @values = {}
9
+ @id = values['id'] if values['id']
10
+ refresh_from(values)
11
+ self.class.define_attribute_methods(attributes.keys)
12
+ end
13
+
14
+ # we will use this method for creating nested resources
15
+ def refresh_from(values)
16
+ values.each do |key, value|
17
+ @values[key] = value
18
+ end
19
+ end
20
+
21
+ def to_s(*opts)
22
+ @values.to_json
23
+ end
24
+
25
+ def inspect
26
+ id_string = !@id.nil? ? " id=#{@id}" : ""
27
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> #{attributes}"
28
+ end
29
+
30
+ def method_missing(name, *opts)
31
+ if name[-1] == '='
32
+ name = name.to_s.gsub(/\=$/, '')
33
+ send(:"#{name}_will_change!")
34
+ @values[name.to_s] = opts.first if @values.has_key?(name.to_s)
35
+ else
36
+ @values[name.to_s] if @values.has_key?(name.to_s)
37
+ end
38
+ end
39
+
40
+ def to_json(*opts)
41
+ CiviCrm::JSON.encode(@values)
42
+ end
43
+
44
+ def as_json(*opts)
45
+ @values.as_json(*a)
46
+ end
47
+
48
+ def to_hash
49
+ @values
50
+ end
51
+
52
+ def attributes
53
+ to_hash.reject{ |k, v| v.is_a? (CiviCrm::Resource)}
54
+ end
55
+
56
+ def attribute(key)
57
+ to_hash[key]
58
+ end
59
+
60
+ class << self
61
+ def entity(name = nil)
62
+ self.entity_name = name
63
+ end
64
+
65
+ def entity_class_name
66
+ self.entity_name.to_s.classify
67
+ end
68
+
69
+ def build_from(resp, request_params = {})
70
+ entity = request_params['entity']
71
+ case resp
72
+ when Array
73
+ resp.map { |values| build_from(values, request_params) }
74
+ when Hash
75
+ klass = "CiviCrm::#{entity.classify}".constantize
76
+ resource = klass.new(resp)
77
+ resource
78
+ else
79
+ resp
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,140 @@
1
+ module CiviCrm
2
+ class BaseResource < CiviCrm::Resource
3
+ include CiviCrm::Actions::List
4
+ include CiviCrm::Actions::Find
5
+ include CiviCrm::Actions::Create
6
+ include CiviCrm::Actions::Update
7
+ include CiviCrm::Actions::Destroy
8
+ end
9
+ end
10
+ module CiviCrm
11
+ class Activity < BaseResource
12
+ entity :activity
13
+ end
14
+ class ActivityType < BaseResource
15
+ entity :activity_type
16
+ end
17
+ class Address < BaseResource
18
+ entity :address
19
+ end
20
+ class Batch < BaseResource
21
+ entity :batch
22
+ end
23
+ class Campaign < BaseResource
24
+ entity :campaign
25
+ end
26
+ class Case < BaseResource
27
+ entity :case
28
+ end
29
+ class Constant < BaseResource
30
+ entity :constant
31
+ end
32
+ class Contact < BaseResource
33
+ entity :contact
34
+ end
35
+ class ContactType < BaseResource
36
+ entity :contact_type
37
+ end
38
+ class Contribution < BaseResource
39
+ entity :contribution
40
+ end
41
+ class ContributionPage < BaseResource
42
+ entity :contribution_page
43
+ end
44
+ class ContributionRecur < BaseResource
45
+ entity :contribution_recur
46
+ end
47
+ class CustomField < BaseResource
48
+ entity :custom_field
49
+ end
50
+ class CustomGroup < BaseResource
51
+ entity :custom_group
52
+ end
53
+ class CustomSearch < BaseResource
54
+ entity :custom_search
55
+ end
56
+ class CustomValue < BaseResource
57
+ entity :custom_value
58
+ end
59
+ class Domain < BaseResource
60
+ entity :domain
61
+ end
62
+ class Email < BaseResource
63
+ entity :email
64
+ end
65
+ class Entity < BaseResource
66
+ entity :entity
67
+ end
68
+ class EntityTag < BaseResource
69
+ entity :entity_tag
70
+ end
71
+ class Event < BaseResource
72
+ entity :event
73
+ end
74
+ class Extension < BaseResource
75
+ entity :extension
76
+ end
77
+ class File < BaseResource
78
+ entity :file
79
+ end
80
+ class Grant < BaseResource
81
+ entity :grant
82
+ end
83
+ class Group < BaseResource
84
+ entity :group
85
+ end
86
+ class GroupContact < BaseResource
87
+ entity :group_contact
88
+ end
89
+ class GroupNesting < BaseResource
90
+ entity :group_nesting
91
+ end
92
+ class GroupOrganization < BaseResource
93
+ entity :group_organization
94
+ end
95
+ class Im < BaseResource
96
+ entity :im
97
+ end
98
+ class Job < BaseResource
99
+ entity :job
100
+ end
101
+ class LineItem < BaseResource
102
+ entity :line_item
103
+ end
104
+ class LocBlock < BaseResource
105
+ entity :loc_block
106
+ end
107
+ class Location < BaseResource
108
+ entity :location
109
+ end
110
+ class LocationType < BaseResource
111
+ entity :location_type
112
+ end
113
+ class MailSettings < BaseResource
114
+ entity :mail_settings
115
+ end
116
+ class Mailing < BaseResource
117
+ entity :mailing
118
+ end
119
+ class Membership < BaseResource
120
+ entity :membership
121
+ end
122
+ class Note < BaseResource
123
+ entity :note
124
+ end
125
+ class Phone < BaseResource
126
+ entity :phone
127
+ end
128
+ class Profile < BaseResource
129
+ entity :profile
130
+ end
131
+ class Setting < BaseResource
132
+ entity :setting
133
+ end
134
+ class Survey < BaseResource
135
+ entity :survey
136
+ end
137
+ class SurveyRespondant < BaseResource
138
+ entity :survey_respondant
139
+ end
140
+ end
@@ -0,0 +1,3 @@
1
+ module CiviCrm
2
+ VERSION = '1.0.1'
3
+ end
@@ -0,0 +1,33 @@
1
+ module CiviCrm
2
+ class XML
3
+ class << self
4
+ def parse(text)
5
+ doc = Nokogiri::XML.parse(text.to_s.gsub("\n", ''))
6
+ results = doc.xpath('//Result')
7
+ results.map do |result|
8
+ hash = {}
9
+ result.children.each do |attribute|
10
+ next unless attribute.is_a?(Nokogiri::XML::Element)
11
+ hash[attribute.name] = attribute.children[0].text rescue nil
12
+ end
13
+ hash
14
+ end
15
+ end
16
+ def encode(resources)
17
+ builder = Nokogiri::XML::Builder.new do |xml|
18
+ xml.ResultSet do
19
+ Array.wrap(resources).each do |resource|
20
+ attributes = resource.respond_to?(:attributes) ? resource.attributes : resource
21
+ xml.Result do
22
+ attributes.each do |key, value|
23
+ xml.send key.to_sym, value
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ builder.to_xml
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+ require 'rest_client'
3
+ require 'ostruct'
4
+ describe "API Bindings" do
5
+
6
+ before :all do
7
+ @client = authorized_civicrm_client
8
+ end
9
+
10
+ it "should not fetch from network while initializing a new Resource" do
11
+ @client.expects(:get).never
12
+ CiviCrm::Contact.new(id: "someid")
13
+ end
14
+
15
+ it "should run authentication" do
16
+ @client.expects(:post).once.returns(test_response(api_key: 'test'))
17
+ CiviCrm.authenticate("test", "test")
18
+ end
19
+
20
+ describe "exception handler" do
21
+
22
+ before :all do
23
+ @client = CiviCrm::Client
24
+ end
25
+
26
+ it "should raise CiviCrm::Errors::BadRequest on 400" do
27
+ exception = RestClient::Exception.new(OpenStruct.new(code: 400, body: 'message'))
28
+ RestClient::Request.stubs(:execute).raises(exception)
29
+ expect { @client.execute!({}) }.to raise_error(CiviCrm::Errors::BadRequest)
30
+ end
31
+
32
+ it "should raise CiviCrm::Errors::Unauthorized on 401" do
33
+ exception = RestClient::Exception.new(OpenStruct.new(code: 401, body: 'message'))
34
+ RestClient::Request.stubs(:execute).raises(exception)
35
+ expect { @client.execute!({}) }.to raise_error(CiviCrm::Errors::Unauthorized)
36
+ end
37
+
38
+ it "should raise CiviCrm::Errors::Forbidden on 403" do
39
+ exception = RestClient::Exception.new(OpenStruct.new(code: 403, body: 'message'))
40
+ RestClient::Request.stubs(:execute).raises(exception)
41
+ expect { @client.execute!({}) }.to raise_error(CiviCrm::Errors::Forbidden)
42
+ end
43
+
44
+ it "should raise CiviCrm::Errors::NotFound on 404" do
45
+ exception = RestClient::Exception.new(OpenStruct.new(code: 404, body: 'message'))
46
+ RestClient::Request.stubs(:execute).raises(exception)
47
+ expect { @client.execute!({}) }.to raise_error(CiviCrm::Errors::NotFound)
48
+ end
49
+
50
+ it "should raise CiviCrm::Errors::InternalError on 500" do
51
+ exception = RestClient::Exception.new(OpenStruct.new(code: 500, body: 'message'))
52
+ RestClient::Request.stubs(:execute).raises(exception)
53
+ expect { @client.execute!({}) }.to raise_error(CiviCrm::Errors::InternalError)
54
+ end
55
+
56
+ it "should raise CiviCrm::Errors::Unauthorized if site_key is not provided" do
57
+ CiviCrm.site_key = nil
58
+ RestClient::Request.stubs(:execute).returns('test')
59
+ expect { @client.request('get', 'test') }.to raise_error(CiviCrm::Errors::Unauthorized)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ describe CiviCrm::Contact do
3
+ it { should be_listable_resource }
4
+ #it { should be_updatable_resource }
5
+
6
+ it "should return contact on create" do
7
+ client = authorized_civicrm_client
8
+
9
+ client.expects(:post).once.returns(test_response(test_contact))
10
+ c = CiviCrm::Contact.create
11
+ c.should be_a_kind_of(CiviCrm::Contact)
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ require 'civicrm'
2
+ require 'support/civicrm'
3
+ require 'support/civicrm_responses'
4
+ require 'support/test_matchers'
5
+ RSpec.configure do |config|
6
+ include CiviCrm::TestResponses
7
+ config.mock_with :mocha
8
+ end
@@ -0,0 +1,27 @@
1
+ module CiviCrm
2
+ class Client
3
+ class << self
4
+ @mock_rest_client = nil
5
+ def mock_rest_client(mock_client)
6
+ @mock_rest_client = mock_client
7
+ end
8
+
9
+ alias_method :execute!, :execute
10
+ def execute(opts)
11
+ get_params = (opts[:headers] || {})[:params]
12
+ post_params = opts[:payload]
13
+ case opts[:method]
14
+ when :get then @mock_rest_client.get opts[:url], get_params, post_params
15
+ when :post then @mock_rest_client.post opts[:url], get_params, post_params
16
+ when :put then @mock_rest_client.put opts[:url], get_params, post_params
17
+ when :delete then @mock_rest_client.delete opts[:url], get_params, post_params
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ def authorized_civicrm_client
24
+ CiviCrm.api_key = 'civicrm'
25
+ CiviCrm.site_key = 'civicrm'
26
+ CiviCrm::Client.mock_rest_client(mock)
27
+ end
@@ -0,0 +1,31 @@
1
+ module CiviCrm::TestResponses
2
+ def test_response(body, code = 200)
3
+ body = CiviCrm::XML.encode(body) if !(body.kind_of? String)
4
+ m = mock
5
+ m.instance_variable_set('@data', { body: body, code: code})
6
+ def m.body; @data[:body]; end
7
+ def m.code; @data[:code]; end
8
+ m
9
+ end
10
+
11
+ def test_contact(params = {})
12
+ {
13
+ :id => '1',
14
+ :contact_id => '1',
15
+ :contact_type => 'Organization',
16
+ :sort_name => 'Inner City Arts',
17
+ :display_name => 'Inner City Arts',
18
+ :name => 'Bruce Lee',
19
+ :description => 'Foo bar',
20
+ :created => '1345537759',
21
+ :livemode => false
22
+ }.merge(params)
23
+ end
24
+
25
+ def test_contact_array
26
+ {
27
+ :count => 3, :is_error => 0,
28
+ :values => [test_contact, test_contact, test_contact]
29
+ }
30
+ end
31
+ end
@@ -0,0 +1,37 @@
1
+ RSpec::Matchers.define :be_listable_resource do |expected|
2
+ match do |actual|
3
+ client = authorized_civicrm_client
4
+ subject = actual.class
5
+ test_response_hash = send(:"test_#{subject.name.demodulize.underscore}_array")
6
+
7
+ client.expects(:get).once.returns(test_response(test_response_hash))
8
+ c = subject.all
9
+
10
+ c.should be_a_kind_of(Array)
11
+ end
12
+ end
13
+ RSpec::Matchers.define :be_updatable_resource do |expected|
14
+ match do |actual|
15
+ client = authorized_civicrm_client
16
+ subject = actual.class
17
+
18
+ client.expects(:get).once.returns(test_response(test_contact({name: "foo"})))
19
+ client.expects(:put).once.returns(test_response(test_contact({name: "bar"})))
20
+ c = subject.find("resource_id")
21
+ c.name.should == "foo"
22
+ c.name = "bar"
23
+ c.save
24
+ c.name.should == "bar"
25
+ end
26
+ end
27
+ RSpec::Matchers.define :be_deleteable_resource do |expected|
28
+ match do |actual|
29
+ client = authorized_civicrm_client
30
+ subject = actual.class
31
+
32
+ client.expects(:get).once.returns(test_response(test_contact({name: "foo"})))
33
+ client.expects(:delete).once.returns(test_response(test_contact({name: "bar"})))
34
+ c = subject.find("resource_id")
35
+ c.delete
36
+ end
37
+ end
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: civicrm
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Iskander Haziev
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.4'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.4'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: activemodel
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: nokogiri
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rspec
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: mocha
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: See http://civicrm.org for details.
127
+ email:
128
+ - gvalmon@gmail.com
129
+ executables:
130
+ - civicrm
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - .gitignore
135
+ - .travis.yml
136
+ - CONTRIBUTORS
137
+ - Gemfile
138
+ - Gemfile.lock
139
+ - History.txt
140
+ - LICENSE
141
+ - README.md
142
+ - Rakefile
143
+ - VERSION
144
+ - bin/civicrm
145
+ - civicrm.gemspec
146
+ - lib/civicrm.rb
147
+ - lib/civicrm/actions/create.rb
148
+ - lib/civicrm/actions/destroy.rb
149
+ - lib/civicrm/actions/find.rb
150
+ - lib/civicrm/actions/list.rb
151
+ - lib/civicrm/actions/update.rb
152
+ - lib/civicrm/client.rb
153
+ - lib/civicrm/errors.rb
154
+ - lib/civicrm/resource.rb
155
+ - lib/civicrm/resources/base.rb
156
+ - lib/civicrm/version.rb
157
+ - lib/civicrm/xml.rb
158
+ - spec/requests/base_spec.rb
159
+ - spec/resources/contact_spec.rb
160
+ - spec/spec_helper.rb
161
+ - spec/support/civicrm.rb
162
+ - spec/support/civicrm_responses.rb
163
+ - spec/support/test_matchers.rb
164
+ homepage: http://civicrm.org
165
+ licenses: []
166
+ post_install_message:
167
+ rdoc_options: []
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ none: false
172
+ requirements:
173
+ - - ! '>='
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ segments:
177
+ - 0
178
+ hash: -4533903245477044172
179
+ required_rubygems_version: !ruby/object:Gem::Requirement
180
+ none: false
181
+ requirements:
182
+ - - ! '>='
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ segments:
186
+ - 0
187
+ hash: -4533903245477044172
188
+ requirements: []
189
+ rubyforge_project:
190
+ rubygems_version: 1.8.25
191
+ signing_key:
192
+ specification_version: 3
193
+ summary: Ruby bindings for the CiviCRM API
194
+ test_files: []