capsule_crm 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 395464813fddf0c08a191e17b395fed06e65c158
4
- data.tar.gz: 391e2918c9f05a3ad4c9362e19bb8adc2b6a4481
3
+ metadata.gz: 1945cc700e9bcf4ac3a29ed1026046b6a5ab287f
4
+ data.tar.gz: bf02c59b07e9b4ac57481dc6c058a2aa564c637e
5
5
  SHA512:
6
- metadata.gz: b5c63e469b2590cafc343352b6127e8251bcb11285f598dfeb0de7296ee279fc24200e34379ba63c9a832f3c68c6ff907da56f5f9e8ad20ffd5e3e135167e6f0
7
- data.tar.gz: d0d215942a05b56c9c1d71181749be9ec3e77ec1b486485e197f35c18c3ba7b3e8915572742c8d648b6848a5a5937905560ac010e364a8ed8d7d8a9484537cb9
6
+ metadata.gz: f3aa284a494b32be73bef69bc8c63a48d0bec998d225295b3065c00ededf8153f0795d2777167f417bccce4439474d5de5d8ffa2608ec6c3131996d4dcc041a3
7
+ data.tar.gz: bf1c4ff048daf6db130a22ffe4ef6748c433d13e9059e472639198f45cc66a740231deb783b2544b33516f29e4918d61e88c81df1433091edf7d615d6016ca31
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - jruby-19mode
6
+ - rbx-19mode
7
+ before_install:
8
+ - gem update --system
9
+ - gem install bundler
10
+ - gem install rake
11
+ script:
12
+ - bundle exec rspec spec/
13
+ bundler_args: --binstubs=./bundler_stubs
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # CapsuleCrm
1
+ # CapsuleCRM
2
2
 
3
- TODO: Write a gem description
3
+ CapsuleCRM provides an ActiveModel compliant interface to the capsulecrm API
4
4
 
5
5
  ## Installation
6
6
 
@@ -18,7 +18,26 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- TODO: Write usage instructions here
21
+ ```ruby
22
+ person = CapsuleCRM::Person.new(first_name: 'Matt', last_name: 'Beedle', organisation_name: "Matt's Company")
23
+ person.save
24
+
25
+ person.first_name = 'John'
26
+ person.save #=> true
27
+
28
+ person.valid? #=> true
29
+
30
+ person.first_name = nil
31
+ person.last_name = nil
32
+ person.valid? #=> false
33
+
34
+ person.save #=> false
35
+ person.save! #=> CapsuleCRM::Errors::InvalidRecord
36
+
37
+ person.destroy #=> true
38
+
39
+ person = CapsuleCRM::Person.create(first_name: 'Matt', last_name: 'Beedle')
40
+ ```
22
41
 
23
42
  ## Contributing
24
43
 
data/capsule_crm.gemspec CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |gem|
20
20
  gem.add_runtime_dependency('activemodel')
21
21
  gem.add_runtime_dependency('activesupport')
22
22
  gem.add_runtime_dependency('faraday')
23
+ gem.add_runtime_dependency('faraday_middleware')
23
24
  gem.add_runtime_dependency('virtus')
24
25
 
25
26
  gem.add_development_dependency('cucumber')
@@ -0,0 +1,17 @@
1
+ module CapsuleCRM
2
+ class Address
3
+ include Virtus
4
+
5
+ extend ActiveModel::Naming
6
+ include ActiveModel::Serializers::JSON
7
+
8
+ include CapsuleCRM::CapsuleJsonable
9
+
10
+ attribute :type
11
+ attribute :street
12
+ attribute :city
13
+ attribute :state
14
+ attribute :zip
15
+ attribute :country
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ module CapsuleCRM
2
+ module CapsuleJsonable
3
+ extend ActiveSupport::Concern
4
+
5
+ def to_capsule_json
6
+ CapsuleCRM::HashHelper.camelize_keys attributes
7
+ end
8
+ end
9
+ end
@@ -15,28 +15,39 @@ module CapsuleCRM
15
15
  end
16
16
 
17
17
  def self.post(path, params)
18
- JSON.parse faraday.post(path, params).body
18
+ response = faraday.post(path, params.to_json) do |request|
19
+ request.headers.update default_request_headers
20
+ end
21
+ if response.success?
22
+ id = response.headers['Location'].match(/\/(?<id>\d+)$/)[:id]
23
+ { id: id }
24
+ else
25
+ false
26
+ end
19
27
  end
20
28
 
21
29
  def self.put(path, params)
22
- JSON.parse faraday.put(path, params).body
30
+ faraday.put(path, params) do |request|
31
+ request.headers.update default_request_headers
32
+ end.success?
23
33
  end
24
34
 
25
- def self.delete(path, params)
26
- JSON.parse faraday.delete(path, params).body
35
+ def self.delete(path)
36
+ faraday.delete(path) do |request|
37
+ request.headers.update default_request_headers
38
+ end.success?
27
39
  end
28
40
 
29
41
  private
30
42
 
31
43
  def self.default_request_headers
32
- {
33
- 'Accept' => 'application/json',
34
- }
44
+ { accept: 'application/json', content_type: 'application/json' }
35
45
  end
36
46
 
37
47
  def self.faraday
38
- Faraday.new("http://#{subdomain}.capsulecrm.com").tap do |connection|
48
+ Faraday.new("https://#{subdomain}.capsulecrm.com").tap do |connection|
39
49
  connection.basic_auth(CapsuleCRM.configuration.api_token, '')
50
+ connection.request :json
40
51
  end
41
52
  end
42
53
 
@@ -0,0 +1,20 @@
1
+ module CapsuleCRM
2
+ module Contactable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ delegate :phones=, to: :contacts
7
+ delegate :websites=, to: :contacts
8
+ delegate :emails=, to: :contacts
9
+ delegate :addresses=, to: :contacts
10
+ end
11
+
12
+ def contacts=(contacts)
13
+ @contacts = contacts
14
+ end
15
+
16
+ def contacts
17
+ @contacts ||= CapsuleCRM::Contacts.new
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,148 @@
1
+ module CapsuleCRM
2
+ class Contacts
3
+
4
+ # Public: Initializes a new CapsuleCRM::Contacts object
5
+ #
6
+ # attributes - The Hash of attributes
7
+ # :addresses - The Array of CapsuleCRM::Address objects
8
+ # :emails - The Array of CapsuleCRM::Email objects
9
+ #
10
+ # Examples
11
+ #
12
+ # CapsuleCRM::Contacts.new
13
+ #
14
+ # CapsuleCRM::Contacts.new(addresses: addresses, emails: emails)
15
+ #
16
+ # Returns a CapsuleCRM::Contact
17
+ def initialize(attributes = {})
18
+ self.addresses = attributes[:addresses]
19
+ self.emails = attributes[:emails]
20
+ self.phones = attributes[:phones]
21
+ self.websites = attributes[:websites]
22
+ end
23
+
24
+ # Public: Sets the addresses for this contacts container
25
+ #
26
+ # addresses - The Array of CapsuleCRM::Address objects
27
+ #
28
+ # Examples
29
+ #
30
+ # address = CapsuleCRM::Address.new(street: 'Oranienburgerstrasse')
31
+ # contacts = CapsuleCRM::Contacts.new
32
+ # contacts.addresses = [address]
33
+ # contacts.addresses << address
34
+ #
35
+ # Returns an Array of CapsuleCRM::Address objects
36
+ def addresses=(addresses)
37
+ @addresses = addresses
38
+ end
39
+
40
+ # Public: Gets the addresses for this contacts container
41
+ #
42
+ # Examples
43
+ #
44
+ # contacts.addresses
45
+ #
46
+ # Returns an Array of CapsuleCRM::Address objects
47
+ def addresses
48
+ @addresses || []
49
+ end
50
+
51
+ # Public: Sets the emails for this contacts container
52
+ #
53
+ # emails - The Array of CapsuleCRM::Email objects
54
+ #
55
+ # Examples
56
+ #
57
+ # email = CapsuleCRM::Email.new(type: 'HOME', email_address:
58
+ # 'matt@gmail.com')
59
+ # contacts = CapsuleCRM::Contacts.new
60
+ # contacts.emails = [email]
61
+ #
62
+ # Returns an Array of CapsuleCRM::Email objects
63
+ def emails=(emails)
64
+ @emails = emails
65
+ end
66
+
67
+ # Public: Gets the emails for this contacts container
68
+ #
69
+ # Examples
70
+ #
71
+ # contacts.emails
72
+ #
73
+ # Returns an Array of CapsuleCRM::Email objects
74
+ def emails
75
+ @emails || []
76
+ end
77
+
78
+ # Public: Sets the phones for this contacts controller
79
+ #
80
+ # phones - The Array of CapsuleCRM::Phone objects
81
+ #
82
+ # Examples
83
+ #
84
+ # phone = CapsuleCRM::Phone.new(type: 'Mobile', phone_number: '1234')
85
+ # contacts = CapsuleCRM::Contacts.new
86
+ # contacts.phones = [phone]
87
+ #
88
+ # Returns an Array of CapsuleCRM::Phone objects
89
+ def phones=(phones)
90
+ @phones = phones
91
+ end
92
+
93
+ # Public: Gets the phones for this contacts container
94
+ #
95
+ # Examples
96
+ #
97
+ # contacts.phones
98
+ #
99
+ # Returns a Hash
100
+ def phones
101
+ @phones || []
102
+ end
103
+
104
+ # Public: Sets the websites for this contacts container
105
+ #
106
+ # websites - The Array of CapsuleCRM::Website objects
107
+ #
108
+ # Examples
109
+ #
110
+ # website = CapsuleCRM::Website.new(
111
+ # type: 'Work', web_service: 'URL', web_address: 'http://github.com'
112
+ # )
113
+ # contacts = CapsuleCRM::Contacts.new
114
+ # contacts.websites = [website]
115
+ #
116
+ # Returns an Array of CapsuleCRM::Website objects
117
+ def websites=(websites)
118
+ @websites = websites
119
+ end
120
+
121
+ # Public: Gets the websites for this contacts container
122
+ #
123
+ # Examples
124
+ #
125
+ # contacts.websites
126
+ #
127
+ # Returns a Hash
128
+ def websites
129
+ @websites || []
130
+ end
131
+
132
+ # Public: Builds a hash of all contact information
133
+ #
134
+ # Examples
135
+ #
136
+ # contacts.to_capsule_json
137
+ #
138
+ # Returns a Hash
139
+ def to_capsule_json
140
+ {
141
+ address: addresses.map(&:to_capsule_json),
142
+ email: emails.map(&:to_capsule_json),
143
+ phone: phones.map(&:to_capsule_json),
144
+ website: websites.map(&:to_capsule_json)
145
+ }.stringify_keys
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,13 @@
1
+ module CapsuleCRM
2
+ class Email
3
+ include Virtus
4
+
5
+ extend ActiveModel::Naming
6
+ include ActiveModel::Serializers::JSON
7
+
8
+ include CapsuleCRM::CapsuleJsonable
9
+
10
+ attribute :type
11
+ attribute :email_address
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ module CapsuleCRM
2
+ module Errors
3
+ class RecordInvalid < StandardError
4
+ end
5
+ end
6
+ end
@@ -10,8 +10,13 @@ module CapsuleCRM
10
10
 
11
11
  def self.camelize_keys!(hash)
12
12
  hash.keys.each do |key|
13
- hash[key.to_s.camelize] = hash.delete(key)
13
+ hash[key.to_s.camelize(:lower)] = hash.delete(key)
14
14
  end
15
15
  end
16
+
17
+ def self.camelize_keys(hash)
18
+ camelize_keys!(hash)
19
+ hash
20
+ end
16
21
  end
17
22
  end
@@ -1,84 +1,251 @@
1
1
  require 'active_support/core_ext'
2
2
 
3
- class CapsuleCRM::Organization
4
- include ::Virtus
5
-
6
- include CapsuleCRM::Associations
7
-
8
- extend ActiveModel::Naming
9
- extend ActiveModel::Callbacks
10
- extend ActiveModel::Conversion
11
- include ActiveModel::Validations
12
- include ActiveModel::Validations::Callbacks
13
-
14
- attribute :name
15
- attribute :about
16
-
17
- # has_many :people
18
-
19
- validates :name, presence: true
20
-
21
- # Public: Get all organizations from Capsule. The list can be restricted
22
- # and/or paginated with various query parameters sent through the options
23
- # hash.
24
- #
25
- # options - The Hash of allowed query parameters for Capsule (default: {}):
26
- # :q - The String search term that will be matched against name,
27
- # telephone number and exact match on searchable custom fields
28
- # :email - The String email address to search for
29
- # :tag - The String tag to search for
30
- # :start - The Integer first record to be returned in pagination.
31
- # The results start with an index of 1
32
- # :limit - The Integer maximum number of matching records to be
33
- # returned
34
- #
35
- # Examples
36
- #
37
- # Organization.all
38
- #
39
- # Organization.all(q: "a search query", start: 10, limit: 20)
40
- #
41
- # Returns a ResultsProxy of organizations
42
- def self.all(options = {})
43
- options.delete_if { |key, value| !allowed_filtering_options.include?(key) }
44
- delete_invalid_options(options)
45
- CapsuleCRM::ResultsProxy.new(
46
- CapsuleCRM::Connection.get('/api/party', options).map do |result|
47
- new(result)
3
+ module CapsuleCRM
4
+ class Organization
5
+ include ::Virtus
6
+
7
+ extend ActiveModel::Naming
8
+ extend ActiveModel::Callbacks
9
+ extend ActiveModel::Conversion
10
+ include ActiveModel::Validations
11
+ include ActiveModel::Validations::Callbacks
12
+
13
+ attribute :name
14
+ attribute :about
15
+
16
+ validates :name, presence: true
17
+
18
+ # Public: Set the attributes of an organization
19
+ #
20
+ # attributes - The Hash of attributes (default: {}):
21
+ # :name - The String organization name
22
+ # :about - The String information about the organization
23
+ #
24
+ # Examples
25
+ #
26
+ # CapsuleCRM::Organization.new
27
+ #
28
+ # Returns a CapsuleCRM::Organization
29
+ def attributes=(attributes)
30
+ CapsuleCRM::HashHelper.underscore_keys!(attributes)
31
+ super(attributes)
32
+ self
33
+ end
34
+
35
+ # Public: Get all people from Capsule. The list can be restricted
36
+ # and/or paginated with various query parameters sent through the options
37
+ # hash.
38
+ #
39
+ # options - The Hash of allowed query parameters for Capsule (default: {}):
40
+ # :q - The String search term that will be matched against
41
+ # name,
42
+ # :tag - The String tag to search for
43
+ # :start - The Integer first record to be returned in
44
+ # pagination.
45
+ # The results start with an index of 1
46
+ # :limit - The Integer maximum number of matching records to be
47
+ # returned
48
+ #
49
+ # Examples
50
+ #
51
+ # CapsuleCRM::Organization.all
52
+ #
53
+ # CapsuleCRM::Organization.all(q: "a search query", start: 10, limit: 20)
54
+ #
55
+ # Returns a ResultsProxy of organisations
56
+ def self.all(options = {})
57
+ init_collection(
58
+ CapsuleCRM::Connection.
59
+ get('/api/party', options)['parties']['organisation']
60
+ )
61
+ end
62
+
63
+ # Public: Get an organization by ID
64
+ #
65
+ # id - The Integer organization ID
66
+ #
67
+ # Examples
68
+ #
69
+ # CapsuleCRM::Organization.find(1)
70
+ #
71
+ # Returns a CapsuleCRM::Organization
72
+ def self.find(id)
73
+ new CapsuleCRM::Connection.get("/api/party/#{id}")['organisation']
74
+ end
75
+
76
+ # Public: Create a new organization in capsulecrm
77
+ #
78
+ # attributes - The Hash of organization attributes (default: {}):
79
+ # :name - The String organization name
80
+ # :about - The String information about the organization
81
+ #
82
+ # Examples
83
+ #
84
+ # CapsuleCRM::Organization.create(name: 'Google Inc')
85
+ #
86
+ # Returns a CapsuleCRM::Organization
87
+ def self.create(attributes = {})
88
+ new(attributes).tap(&:save)
89
+ end
90
+
91
+ # Public: Create a new organization in capsulecrm and raise a
92
+ # CapsuleCRM::Errors::InvalidRecord error if not possible
93
+ #
94
+ # attributes - The Hash of organization attributes (default: {}):
95
+ # :name - The String organization name
96
+ # :about - The String information about the organization
97
+ #
98
+ # Examples
99
+ #
100
+ # CapsuleCRM::Organization.create!(name: 'Google Inc')
101
+ #
102
+ # Returns a CapsuleCRM
103
+ def self.create!(attributes = {})
104
+ new(attributes).tap(&:save!)
105
+ end
106
+
107
+ # Public: If the organization already exists in capsule then update them,
108
+ # otherwise create a new organization
109
+ #
110
+ # Examples
111
+ #
112
+ # organization = CapsuleCRM::Organization.new(name: 'Google Inc')
113
+ # organization.save
114
+ #
115
+ # organization = CapsuleCRM::Organization.find(1)
116
+ # organization.name = 'Apple'
117
+ # organization.save
118
+ #
119
+ # Returns a CapsuleCRM::Organization
120
+ def save
121
+ if valid?
122
+ new_record? ? create_record : update_record
123
+ else
124
+ false
48
125
  end
49
- )
50
- end
126
+ end
51
127
 
52
- def self.find(id)
53
- new CapsuleCRM::Connection.get("/api/party/#{id}")
54
- end
128
+ # Public: If the organization already exists in capsule then update them,
129
+ # otherwise create a new organization. If the organization is not valid
130
+ # then a CapsuleCRM::Errors::RecordInvalid exception is raised
131
+ #
132
+ # Examples
133
+ #
134
+ # organization = CapsuleCRM::Organization.new(name: 'Google Inc')
135
+ # organization.save!
136
+ #
137
+ # organization = CapsuleCRM::Organization.find(1)
138
+ # organization.name = 'Apple'
139
+ # organization.save!
140
+ #
141
+ # organization = CapsuleCRM::Organization.new
142
+ # organization.save!
143
+ # => CapsuleCRM::Errors::InvalidRecord
144
+ #
145
+ # Returns a CapsuleCRM::Organization
146
+ def save!
147
+ if valid?
148
+ new_record ? create_record : update_record
149
+ else
150
+ raise CapsuleCRM::Errors::RecordInvalid.new(self)
151
+ end
152
+ end
55
153
 
56
- def save
57
- if new_record?
58
- create(attributes)
59
- else
60
- update(attributes)
154
+ # Public: Update the organization in capsule
155
+ #
156
+ # attributes - The Hash of organization attributes (default: {}):
157
+ # :name - The String organization name
158
+ # :about - The String information about the organization
159
+ #
160
+ # Examples
161
+ #
162
+ # organization = CapsuleCRM::Organization.find(1)
163
+ # organization.update_attributes name: 'Google Inc'
164
+ # => true
165
+ #
166
+ # organization.update_attributes {}
167
+ # => false
168
+ #
169
+ # Returns a CapsuleCRM::Organization
170
+ def update_attributes(attributes = {})
171
+ self.attributes = attributes
172
+ save
61
173
  end
62
- end
63
174
 
64
- def create(attributes = {})
65
- CapsuleCRM::Connection.post('/api/organization', attributes)
66
- end
175
+ # Public: Update the organization in capsule. If the organization is not
176
+ # valid then a CapsuleCRM::Errors::RecordInvalid exception will be raised
177
+ #
178
+ # attributes - The Hash of organization attributes (default: {}):
179
+ # :name - The String organization name
180
+ # :about - The String information about the organization
181
+ #
182
+ # Examples
183
+ #
184
+ # organization = CapsuleCRM::Organization.find(1)
185
+ # organization.update_attributes! name: 'Microsoft'
186
+ # => true
187
+ #
188
+ # organization = CapsuleCRM::Organization.find(1)
189
+ # organization.update_attributes!
190
+ # => CapsuleCRM::Errors::RecordInvalid
191
+ #
192
+ # Returns a CapsuleCRM::Organization
193
+ def update_attributes!(attributes = {})
194
+ self.attributes = attributes
195
+ save!
196
+ end
67
197
 
68
- def update_attributes(attributes = {})
69
- CapsuleCRM::Connection.put("/api/organization/#{id}", attributes)
70
- end
198
+ # Public: Determine whether this CapsuleCRM::Organization is a new record
199
+ # or not
200
+ #
201
+ # Returns a Boolean
202
+ def new_record?
203
+ !id
204
+ end
71
205
 
72
- private
206
+ # Public: Determine whether or not this CapsuleCRM::Organization has
207
+ # already been persisted to capsulecrm
208
+ #
209
+ # Returns a Boolean
210
+ def persisted?
211
+ !new_record?
212
+ end
73
213
 
74
- def delete_invalid_all_options(options)
75
- options.stringify_keys!
76
- options.delete_if do |key, value|
77
- !allowed_filtering_options.include?(key)
214
+ # Public: Build a hash of attributes and merge in the attributes for the
215
+ # contact information
216
+ #
217
+ # Examples
218
+ #
219
+ # organization.to_capsule_json
220
+ #
221
+ # Returns a Hash
222
+ def to_capsule_json
223
+ {
224
+ organisation: attributes.merge(contacts: contacts.to_capsule_json).
225
+ stringify_keys
226
+ }.stringify_keys
227
+ end
228
+
229
+ private
230
+
231
+ def create_record
232
+ self.attributes = CapsuleCRM::Connection.post(
233
+ '/api/organisation', to_capsule_json
234
+ )
235
+ end
236
+
237
+ def update_record
238
+ CapsuleCRM::Connection.put("/api/organisation/#{id}", attributes)
78
239
  end
79
- end
80
240
 
81
- def allowed_filtering_options
82
- %w(q email last_modified tag start limit)
241
+ # Private: Build a ResultsProxy from a Array of CapsuleCRM::Organization
242
+ # attributes
243
+ #
244
+ # collection - The Array of CapsuleCRM::Organization attributes hashes
245
+ #
246
+ # Returns a CapsuleCRM::ResultsProxy
247
+ def self.init_collection(collection)
248
+ CapsuleCRM::ResultsProxy.new(collection.map { |item| new item })
249
+ end
83
250
  end
84
251
  end