capsule_crm 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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