agilecrm-wrapper 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,75 @@
1
+ module AgileCRMWrapper
2
+ class Error < StandardError
3
+ attr_reader :response
4
+
5
+ class << self
6
+ def from_response(response, message = '')
7
+ new(response, message)
8
+ end
9
+
10
+ def errors
11
+ @errors ||= {
12
+ 400 => AgileCRMWrapper::BadRequest,
13
+ 401 => AgileCRMWrapper::Unauthorized,
14
+ 404 => AgileCRMWrapper::NotFound,
15
+ 405 => AgileCRMWrapper::MethodNotAllowed,
16
+ 415 => AgileCRMWrapper::MediaTypeMismatch,
17
+ 500 => AgileCRMWrapper::InternalServerError
18
+ }
19
+ end
20
+ end
21
+
22
+ def initialize(response, message = '')
23
+ super(message)
24
+ @response = response
25
+ end
26
+ end
27
+
28
+ # Raised when Twitter returns a 4xx HTTP status code
29
+ class ClientError < Error; end
30
+
31
+ # Raised when AgileCRMWrapper returns a 400 HTTP status code
32
+ class BadRequest < ClientError
33
+ def initialize(response, message = 'The request was formatted incorrectly')
34
+ super(response, message)
35
+ end
36
+ end
37
+
38
+ # Raised when AgileCRMWrapper returns a 401 HTTP status code
39
+ class Unauthorized < ClientError
40
+ def initialize(response, message = 'Invalid API Key')
41
+ super(response, message)
42
+ end
43
+ end
44
+
45
+ # Raised when AgileCRMWrapper returns a 404 HTTP status code
46
+ class NotFound < ClientError
47
+ def initialize(response, message = 'Resource not found')
48
+ super(response, message)
49
+ end
50
+ end
51
+
52
+ # Raised when AgileCRMWrapper returns a 405 HTTP status code
53
+ class MethodNotAllowed < ClientError
54
+ def initialize(response, message = 'Invalid method type')
55
+ super(response, message)
56
+ end
57
+ end
58
+
59
+ # Raised when AgileCRMWrapper returns a 415 HTTP status code
60
+ class MediaTypeMismatch < ClientError
61
+ def initialize(response, message = 'Unsupported Media type')
62
+ super(response, message)
63
+ end
64
+ end
65
+
66
+ # Raised when AgileCRMWrapper returns a 5xx HTTP status code
67
+ class ServerError < Error; end
68
+
69
+ # Raised when AgileCRMWrapper returns a 500 HTTP status code
70
+ class InternalServerError < ServerError
71
+ def initialize(response, message = 'Server error')
72
+ super(response, message)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,31 @@
1
+ require 'agilecrm-wrapper/error'
2
+ require 'hashie'
3
+
4
+ module AgileCRMWrapper
5
+ class Note < Hashie::Mash
6
+ class << self
7
+ def create(*contacts, subject: '', description: '')
8
+ contacts = contacts.flatten.uniq.map(&:to_s)
9
+ payload = {
10
+ 'subject' => subject,
11
+ 'description' => description,
12
+ 'contact_ids' => contacts
13
+ }
14
+ response = AgileCRMWrapper.connection.post('notes', payload)
15
+ new(response.body)
16
+ end
17
+
18
+ def add_by_email(email: '', subject: '', description: '')
19
+ payload = {
20
+ 'subject' => subject,
21
+ 'description' => description
22
+ }
23
+ query = "email=#{email}&note=#{payload.to_json}"
24
+ AgileCRMWrapper.connection.post(
25
+ 'contacts/email/note/add', query,
26
+ 'content-type' => 'application/x-www-form-urlencoded'
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ require 'faraday'
2
+ require 'agilecrm-wrapper/error'
3
+
4
+ module AgileCRMWrapper
5
+ module Response
6
+ class RaiseError < Faraday::Response::Middleware
7
+ private
8
+
9
+ def on_complete(response)
10
+ status_code = response.status.to_i
11
+ klass = AgileCRMWrapper::Error.errors[status_code]
12
+ return unless klass
13
+ fail(klass.from_response(response))
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ Faraday::Response.register_middleware(
20
+ agilecrm_error: AgileCRMWrapper::Response::RaiseError
21
+ )
@@ -0,0 +1,3 @@
1
+ module AgileCRMWrapper
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe AgileCRMWrapper do
4
+ let(:domain) { 'mydomain' }
5
+ let(:api_key) { 'xxx' }
6
+ let(:email) { 'email@example.com' }
7
+
8
+ describe 'configuration' do
9
+ before(:each) do
10
+ AgileCRMWrapper.configure do |config|
11
+ config.domain = domain
12
+ config.api_key = api_key
13
+ config.email = email
14
+ end
15
+ end
16
+
17
+ after :each do
18
+ AgileCRMWrapper.reset
19
+ end
20
+
21
+ describe '.configure' do
22
+ it 'has a custom configuration' do
23
+ expect(AgileCRMWrapper.configuration.domain).to match domain
24
+ expect(AgileCRMWrapper.configuration.api_key).to match api_key
25
+ expect(AgileCRMWrapper.configuration.email).to match email
26
+ end
27
+
28
+ its(:endpoint) { should eq 'https://mydomain.agilecrm.com/dev/api' }
29
+ end
30
+
31
+ describe '.reset' do
32
+ before(:each) do
33
+ AgileCRMWrapper.configure do |config|
34
+ config.email = email
35
+ end
36
+ end
37
+
38
+ it 'resets the configuration' do
39
+ AgileCRMWrapper.reset
40
+ config = AgileCRMWrapper.configuration
41
+ expect(config.email).to eq ''
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe AgileCRMWrapper::Contact do
4
+ let(:contact) { AgileCRMWrapper::Contact.find(123) }
5
+
6
+ describe '.all' do
7
+ subject { AgileCRMWrapper::Contact.all }
8
+
9
+ it 'should return an array of Contacts' do
10
+ expect(subject.map(&:class).uniq).to eq([AgileCRMWrapper::Contact])
11
+ end
12
+ end
13
+
14
+ describe '.find' do
15
+ let(:id) { 123 }
16
+ subject { AgileCRMWrapper::Contact.find(id) }
17
+
18
+ context 'given an existing contact ID' do
19
+ it { should be_kind_of(AgileCRMWrapper::Contact) }
20
+
21
+ its(:id) { should eq id }
22
+ end
23
+
24
+ context 'given an unknown contact ID' do
25
+ let(:id) { 0 }
26
+ it { expect { is_expected.to raise_error(AgileCRMWrapper::NotFound) } }
27
+ end
28
+ end
29
+
30
+ describe '.delete' do
31
+ context 'given a single ID' do
32
+ subject { AgileCRMWrapper::Contact.delete(123) }
33
+
34
+ its(:status) { should eq 204 }
35
+ end
36
+ end
37
+
38
+ describe '.search_by_email' do
39
+ let(:email) { 'anitadrink@example.com' }
40
+ subject { AgileCRMWrapper::Contact.search_by_email(email) }
41
+
42
+ context 'given an existing email' do
43
+ it 'should return a contact with the corresponding email' do
44
+ expect(subject.get_property('email')).to eq email
45
+ end
46
+ end
47
+
48
+ context 'given an non-existing email' do
49
+ let(:email) { 'idontexist@example.com' }
50
+
51
+ it 'should return an empty array' do
52
+ expect(subject).to eq nil
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '.create' do
58
+ subject do
59
+ AgileCRMWrapper::Contact.create(
60
+ tags: %w(sales, rspec), first_name: 'Anita',
61
+ last_name: 'Drink', email: 'anitadrink@example.com',
62
+ custom_field: 'Im a custom field!'
63
+ )
64
+ end
65
+
66
+ its(:status) { should eq 201 }
67
+ end
68
+
69
+ describe '#notes' do
70
+ it 'returns the associated notes' do
71
+ expect(contact.notes.map(&:class).uniq).to eq [AgileCRMWrapper::Note]
72
+ end
73
+ end
74
+
75
+ describe '#update' do
76
+
77
+ it 'updates the receiving contact with the supplied key-value pair(s)' do
78
+ expect do
79
+ contact.update(first_name: 'Foo!')
80
+ end.to change{
81
+ contact.get_property('first_name')
82
+ }.from('Anita').to('Foo!')
83
+ end
84
+ end
85
+
86
+ describe '#get_property' do
87
+ let(:contact) { AgileCRMWrapper::Contact.find(123) }
88
+
89
+ context 'supplied an existing property name' do
90
+ it 'returns the value' do
91
+ expect(contact.get_property('email')).to_not be_nil
92
+ end
93
+ end
94
+
95
+ context 'supplied a non-existing property name' do
96
+ it 'returns nil' do
97
+ expect(contact.get_property('nil-propety')).to be_nil
98
+ end
99
+ end
100
+ end
101
+
102
+ describe '#destroy' do
103
+ let(:contact) { AgileCRMWrapper::Contact.find(123) }
104
+ subject { contact.destroy }
105
+
106
+ its(:status) { should eq 204 }
107
+ end
108
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe AgileCRMWrapper::Note do
4
+ describe '.create' do
5
+ it 'creates a new note' do
6
+ expect(
7
+ AgileCRMWrapper::Note.create(123, subject: '', description: '')
8
+ ).to be_kind_of(AgileCRMWrapper::Note)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ {
2
+ "id": 123,
3
+ "type": "PERSON",
4
+ "created_time": 1412704793,
5
+ "updated_time": 0,
6
+ "viewed_time": 0,
7
+ "viewed": {
8
+ "viewed_time": 0
9
+ },
10
+ "star_value": 0,
11
+ "lead_score": 0,
12
+ "tags": ["sales", "rspec"],
13
+ "tagsWithTime": [{
14
+ "tag": "sales",
15
+ "createdTime": 1412704793874,
16
+ "availableCount": 0,
17
+ "entity_type": "tag"
18
+ }, {
19
+ "tag": "rspec",
20
+ "createdTime": 1412704793874,
21
+ "availableCount": 0,
22
+ "entity_type": "tag"
23
+ }],
24
+ "properties": [{
25
+ "type": "SYSTEM",
26
+ "name": "first_name",
27
+ "value": "Anita"
28
+ }, {
29
+ "type": "SYSTEM",
30
+ "name": "last_name",
31
+ "value": "Drink"
32
+ }, {
33
+ "type": "SYSTEM",
34
+ "name": "email",
35
+ "value": "anitadrink@example.com"
36
+ }, {
37
+ "type": "CUSTOM",
38
+ "name": "custom_field",
39
+ "value": "Im a custom field!"
40
+ }],
41
+ "campaignStatus": [],
42
+ "entity_type": "contact_entity",
43
+ "unsubscribeStatus": [],
44
+ "emailBounceStatus": []
45
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "id": 123,
3
+ "type": "PERSON",
4
+ "created_time": 1412704793,
5
+ "updated_time": 0,
6
+ "viewed_time": 0,
7
+ "viewed": {
8
+ "viewed_time": 0
9
+ },
10
+ "star_value": 0,
11
+ "lead_score": 0,
12
+ "tags": ["sales", "rspec"],
13
+ "tagsWithTime": [{
14
+ "tag": "sales",
15
+ "createdTime": 1412704793874,
16
+ "availableCount": 0,
17
+ "entity_type": "tag"
18
+ }, {
19
+ "tag": "rspec",
20
+ "createdTime": 1412704793874,
21
+ "availableCount": 0,
22
+ "entity_type": "tag"
23
+ }],
24
+ "properties": [{
25
+ "type": "SYSTEM",
26
+ "name": "first_name",
27
+ "value": "Anita"
28
+ }, {
29
+ "type": "SYSTEM",
30
+ "name": "last_name",
31
+ "value": "Drink"
32
+ }, {
33
+ "type": "SYSTEM",
34
+ "name": "email",
35
+ "value": "anitadrink@example.com"
36
+ }, {
37
+ "type": "CUSTOM",
38
+ "name": "custom_field",
39
+ "value": "Im a custom field!"
40
+ }],
41
+ "campaignStatus": [],
42
+ "entity_type": "contact_entity",
43
+ "unsubscribeStatus": [],
44
+ "emailBounceStatus": []
45
+ }
@@ -0,0 +1,52 @@
1
+ [{
2
+ "id": 80001,
3
+ "created_time": 1360561958,
4
+ "subject": "Note subject",
5
+ "description": "Note description",
6
+ "contacts": [{
7
+ "id": 123,
8
+ "type": "PERSON",
9
+ "created_time": 1412704793,
10
+ "updated_time": 0,
11
+ "viewed_time": 0,
12
+ "viewed": {
13
+ "viewed_time": 0
14
+ },
15
+ "star_value": 0,
16
+ "lead_score": 0,
17
+ "tags": ["sales", "rspec"],
18
+ "tagsWithTime": [{
19
+ "tag": "sales",
20
+ "createdTime": 1412704793874,
21
+ "availableCount": 0,
22
+ "entity_type": "tag"
23
+ }, {
24
+ "tag": "rspec",
25
+ "createdTime": 1412704793874,
26
+ "availableCount": 0,
27
+ "entity_type": "tag"
28
+ }],
29
+ "properties": [{
30
+ "type": "SYSTEM",
31
+ "name": "first_name",
32
+ "value": "Anita"
33
+ }, {
34
+ "type": "SYSTEM",
35
+ "name": "last_name",
36
+ "value": "Drink"
37
+ }, {
38
+ "type": "SYSTEM",
39
+ "name": "email",
40
+ "value": "anitadrink@example.com"
41
+ }, {
42
+ "type": "CUSTOM",
43
+ "name": "custom_field",
44
+ "value": "Im a custom field!"
45
+ }],
46
+ "campaignStatus": [],
47
+ "entity_type": "contact_entity",
48
+ "unsubscribeStatus": [],
49
+ "emailBounceStatus": []
50
+ }],
51
+ "entity_type": "note"
52
+ }]