amorail 0.1.4 → 0.1.5

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: 9c91d42f4e1991fe27ebde64b7e88f8537c90ad7
4
- data.tar.gz: 18665c9622339679e5d419d7dec829e1c736ad6c
3
+ metadata.gz: d0fe2be0f031e806dd9eac0da0ac09ee4a9b5d79
4
+ data.tar.gz: ae1153aee232f6d0b30190a68e0e2b2e9d15cdd7
5
5
  SHA512:
6
- metadata.gz: 2b4b928c8a32c0a3ed07fa0e8aed9c916cfd401ebed5c97bcc989d9e71dd37d9ee5b6b9f559a0a504949c0a78198c05dacb7b3efcd7217279e603838f442c713
7
- data.tar.gz: 514dc9cbbfc728f82d240208b71d202f0fb129e3ee3457c19ecb08c6c6a0b951df45749652e75e44dde6903113af66e80ad175bbce274840babcf22e0091a1f5
6
+ metadata.gz: 32b9fb3a98d3ac82dd40e9c7fd4f9aeb079d8f942a72f98428de7bf13712a1edea8d2b7562e16974d8ddadd4e80024e5119ca79d3e6cb6a7118535367922e312
7
+ data.tar.gz: 224079bf6eb4bb040a72386fd589b0f4aca5bb76df7a1c69ba9e6cd923e9064db53ab3c8d7be3f941f891df2bfb0932b0e56499ba64b9c7637977eafedf2558c
data/.gitignore CHANGED
@@ -7,7 +7,6 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
- /lib/amorail/entities/
11
10
  *.bundle
12
11
  *.so
13
12
  *.o
data/.hound.yml CHANGED
@@ -1,2 +1,12 @@
1
1
  ruby:
2
2
  enabled: true
3
+ config_file: .rubocop.yml
4
+
5
+ javascript:
6
+ enabled: false
7
+
8
+ coffeescript:
9
+ enabled: false
10
+
11
+ sass:
12
+ enabled: false
data/.rubocop.yml CHANGED
@@ -16,3 +16,17 @@ Style/Documentation:
16
16
 
17
17
  Style/StringLiterals:
18
18
  Enabled: false
19
+
20
+ Style/BlockDelimiters:
21
+ Exclude:
22
+ - 'spec/**/*.rb'
23
+
24
+ Metrics/MethodLength:
25
+ Exclude:
26
+ - 'spec/**/*.rb'
27
+
28
+ Rails/Date:
29
+ Enabled: false
30
+
31
+ Rails/TimeZone:
32
+ Enabled: false
@@ -4,14 +4,15 @@ require 'json'
4
4
  require 'active_support'
5
5
 
6
6
  module Amorail
7
+ # Amorail http client
7
8
  class Client
8
9
  attr_accessor :cookies
9
10
 
10
11
  def initialize
11
12
  @host = Amorail.config.api_endpoint
12
- @connect = Faraday.new(url: @host) do |faraday|
13
- faraday.adapter Faraday.default_adapter
14
- faraday.response :json, :content_type => /\bjson$/
13
+ @connect = Faraday.new(url: @host) do |faraday|
14
+ faraday.adapter Faraday.default_adapter
15
+ faraday.response :json, content_type: /\bjson$/
15
16
  faraday.use :instrumentation
16
17
  end
17
18
  end
@@ -19,30 +20,34 @@ module Amorail
19
20
  def connect
20
21
  @connect || self.class.new
21
22
  end
22
-
23
+
23
24
  def authorize
24
- response = post(Amorail.config.auth_url, {'USER_LOGIN' => Amorail.config.usermail, 'USER_HASH' => Amorail.config.api_key})
25
+ response = post(
26
+ Amorail.config.auth_url,
27
+ 'USER_LOGIN' => Amorail.config.usermail,
28
+ 'USER_HASH' => Amorail.config.api_key
29
+ )
25
30
  cookie_handler(response)
26
31
  response
27
32
  end
28
-
29
- def safe_request(method, url, params={})
30
- self.send(method, url, params)
31
- rescue ::Amorail::AmoUnauthorizedError => e
33
+
34
+ def safe_request(method, url, params = {})
35
+ send(method, url, params)
36
+ rescue ::Amorail::AmoUnauthorizedError
32
37
  authorize
33
- self.send(method, url, params)
38
+ send(method, url, params)
34
39
  end
35
40
 
36
- def get(url, params={})
41
+ def get(url, params = {})
37
42
  response = connect.get(url, params) do |request|
38
- request.headers['Cookie'] = self.cookies if self.cookies.present?
43
+ request.headers['Cookie'] = cookies if cookies.present?
39
44
  end
40
45
  handle_response(response)
41
46
  end
42
47
 
43
- def post(url, params={})
48
+ def post(url, params = {})
44
49
  response = connect.post(url) do |request|
45
- request.headers['Cookie'] = self.cookies if self.cookies.present?
50
+ request.headers['Cookie'] = cookies if cookies.present?
46
51
  request.headers['Content-Type'] = 'application/json'
47
52
  request.body = params.to_json
48
53
  end
@@ -53,29 +58,29 @@ module Amorail
53
58
  self.cookies = response.headers['set-cookie'].split('; ')[0]
54
59
  end
55
60
 
56
- def handle_response(response)
57
- return response if response.status == 200 or response.status == 204
58
-
61
+ def handle_response(response) # rubocop:disable all
62
+ return response if response.status == 200 || response.status == 204
63
+
59
64
  case response.status
60
65
  when 301
61
- raise ::Amorail::AmoMovedPermanentlyError
66
+ fail ::Amorail::AmoMovedPermanentlyError
62
67
  when 400
63
- raise ::Amorail::AmoBadRequestError
64
- when 401
65
- raise ::Amorail::AmoUnauthorizedError
68
+ fail ::Amorail::AmoBadRequestError
69
+ when 401
70
+ fail ::Amorail::AmoUnauthorizedError
66
71
  when 403
67
- raise ::Amorail::AmoForbiddenError
72
+ fail ::Amorail::AmoForbiddenError
68
73
  when 404
69
- raise ::Amorail::AmoNotFoudError
74
+ fail ::Amorail::AmoNotFoudError
70
75
  when 500
71
- raise ::Amorail::AmoInternalError
76
+ fail ::Amorail::AmoInternalError
72
77
  when 502
73
- raise ::Amorail::AmoBadGatewayError
78
+ fail ::Amorail::AmoBadGatewayError
74
79
  when 503
75
- raise ::Amorail::AmoServiceUnaviableError
80
+ fail ::Amorail::AmoServiceUnaviableError
76
81
  else
77
- raise ::Amorail::AmoUnknownError(response.body)
82
+ fail ::Amorail::AmoUnknownError(response.body)
78
83
  end
79
84
  end
80
85
  end
81
- end
86
+ end
@@ -1,6 +1,12 @@
1
1
  require 'anyway'
2
2
 
3
3
  module Amorail
4
+ # Amorail config contains:
5
+ # - usermail ("user@gmail.com")
6
+ # - api_key ("13601bbac84727df")
7
+ # - api_endpoint ("http://you_company.amocrm.com")
8
+ # - api_path (default: "/private/api/v2/json/")
9
+ # - auth_url (default: "/private/api/auth.php?type=json")
4
10
  class Config < Anyway::Config
5
11
  attr_config :usermail,
6
12
  :api_key,
@@ -8,4 +14,4 @@ module Amorail
8
14
  api_path: "/private/api/v2/json/",
9
15
  auth_url: "/private/api/auth.php?type=json"
10
16
  end
11
- end
17
+ end
@@ -2,10 +2,11 @@ require 'amorail'
2
2
  require 'rails'
3
3
 
4
4
  module Amorail
5
+ # Amorail Rails engine
6
+ # Load Amorails rake tasks
5
7
  class Engine < Rails::Engine
6
8
  rake_tasks do
7
9
  load File.expand_path("../../tasks/amorail.rake", __FILE__)
8
10
  end
9
11
  end
10
12
  end
11
-
@@ -1,4 +1,7 @@
1
+ require 'amorail/entities/leadable'
2
+
1
3
  module Amorail
4
+ # AmoCRM company entity
2
5
  class AmoCompany < Amorail::AmoEntity
3
6
  include Leadable
4
7
  amo_names 'company', 'contacts'
@@ -1,12 +1,15 @@
1
+ require 'amorail/entities/leadable'
2
+
1
3
  module Amorail
4
+ # AmoCRM contact entity
2
5
  class AmoContact < Amorail::AmoEntity
3
6
  include Leadable
4
7
  amo_names 'contacts'
5
8
 
6
9
  amo_field :name, :company_name
7
10
 
8
- amo_property :email, enum: 'MOB'
9
- amo_property :phone, enum: 'WORK'
11
+ amo_property :email, enum: 'WORK'
12
+ amo_property :phone, enum: 'MOB'
10
13
  amo_property :position
11
14
 
12
15
  validates :name, presence: true
@@ -1,4 +1,5 @@
1
1
  module Amorail
2
+ # AmoCRM lead entity
2
3
  class AmoLead < Amorail::AmoEntity
3
4
  amo_names "leads"
4
5
 
@@ -0,0 +1,6 @@
1
+ module Amorail
2
+ # Lead associations
3
+ module Leadable
4
+ # TODO: !!!
5
+ end
6
+ end
@@ -1,4 +1,5 @@
1
1
  module Amorail
2
+ # AmoCRM task entity
2
3
  class AmoTask < Amorail::AmoEntity
3
4
  amo_names "tasks"
4
5
 
@@ -12,21 +13,6 @@ module Amorail
12
13
 
13
14
  validates :element_type, inclusion: 1..2
14
15
 
15
- def params
16
- {
17
- id: id,
18
- text: text,
19
- date_create: to_timestamp(date_create),
20
- last_modified: to_timestamp(last_modified) || Time.now.to_i,
21
- request_id: request_id,
22
- responsible_user_id: responsible_user_id,
23
- element_id: element_id,
24
- element_type: element_type,
25
- task_type: task_type,
26
- complete_till: to_timestamp(complete_till)
27
- }
28
- end
29
-
30
16
  [{ name: "contact", val: 1 }, { name: "lead", val: 2 }].each do |prop|
31
17
  class_eval <<-CODE, __FILE__, __LINE__ + 1
32
18
  def #{prop[:name]}=(val)
@@ -0,0 +1,30 @@
1
+ module Amorail # :nodoc: all
2
+ class AmoEntity
3
+ class << self
4
+ def find(id)
5
+ new.load_record(id)
6
+ end
7
+
8
+ def find!(id)
9
+ rec = find(id)
10
+ fail RecordNotFound unless rec
11
+ rec
12
+ end
13
+ end
14
+
15
+ def load_record(id)
16
+ response = client.safe_request(
17
+ :get,
18
+ remote_url('list'),
19
+ id: id
20
+ )
21
+ handle_response(response, 'load')
22
+ end
23
+
24
+ private
25
+
26
+ def extract_data_load(response)
27
+ response.first
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,95 @@
1
+ module Amorail # :nodoc: all
2
+ class AmoEntity
3
+ def params
4
+ data = {}
5
+ self.class.attributes.each do |k, v|
6
+ data[k] = send("to_#{v}", send(k))
7
+ end
8
+
9
+ data[:custom_fields] = custom_fields if properties.respond_to?(amo_name)
10
+
11
+ normalize_params(data)
12
+ end
13
+
14
+ protected
15
+
16
+ def custom_fields
17
+ props = properties.send(self.class.amo_name)
18
+
19
+ custom_fields = []
20
+
21
+ self.class.properties.each do |k, v|
22
+ prop_id = props.send(k).id
23
+ prop_val = { value: send(k) }.merge(v)
24
+ custom_fields << { id: prop_id, values: [prop_val] }
25
+ end
26
+
27
+ custom_fields
28
+ end
29
+
30
+ def create_params(method)
31
+ {
32
+ request: {
33
+ self.class.amo_response_name => {
34
+ method => [
35
+ params
36
+ ]
37
+ }
38
+ }
39
+ }
40
+ end
41
+
42
+ def normalize_custom_fields(val)
43
+ val.reject do |field|
44
+ field[:values].all? { |item| !item[:value] }
45
+ end
46
+ end
47
+
48
+ # this method removes nil values and empty arrays from params hash (deep)
49
+ # rubocop:disable Metrics/AbcSize
50
+ # rubocop:disable Metrics/CyclomaticComplexity
51
+ # rubocop:disable Metrics/MethodLength
52
+ def normalize_params(data)
53
+ return data unless data.is_a?(Hash)
54
+
55
+ compacted = {}
56
+ data.each do |key, val|
57
+ case val
58
+ when Numeric, String
59
+ compacted[key] = val
60
+ when Array
61
+ val.compact!
62
+ # handle custom keys
63
+ val = normalize_custom_fields(val) if key == :custom_fields
64
+ unless val.empty?
65
+ compacted[key] = val.map { |el| normalize_params(el) }
66
+ end
67
+ else
68
+ params = normalize_params(val)
69
+ compacted[key] = params unless params.nil?
70
+ end
71
+ end
72
+ compacted.with_indifferent_access
73
+ end
74
+ # rubocop:enable Metrics/AbcSize
75
+ # rubocop:enable Metrics/CyclomaticComplexity
76
+ # rubocop:enable Metrics/MethodLength
77
+
78
+ def to_timestamp(val)
79
+ return if val.nil?
80
+
81
+ case val
82
+ when String
83
+ (date = Time.parse(val)) && date.to_i
84
+ when Date
85
+ val.to_time.to_i
86
+ else
87
+ val.to_i
88
+ end
89
+ end
90
+
91
+ def to_default(val)
92
+ val
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,47 @@
1
+ module Amorail # :nodoc: all
2
+ class AmoEntity
3
+ class InvalidRecord < ::Amorail::Error; end
4
+ class NotPersisted < ::Amorail::Error; end
5
+
6
+ def new_record?
7
+ id.blank?
8
+ end
9
+
10
+ def persisted?
11
+ !new_record?
12
+ end
13
+
14
+ def save
15
+ return false unless valid?
16
+ new_record? ? push('add') : push('update')
17
+ end
18
+
19
+ def save!
20
+ if save
21
+ true
22
+ else
23
+ fail InvalidRecord
24
+ end
25
+ end
26
+
27
+ def update(attrs = {})
28
+ return false if new_record?
29
+ merge_params(attrs)
30
+ push('update')
31
+ end
32
+
33
+ def update!(attrs = {})
34
+ if update(attrs)
35
+ true
36
+ else
37
+ fail NotPersisted
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def extract_data_add(response)
44
+ response.fetch('add').first
45
+ end
46
+ end
47
+ end
@@ -1,17 +1,16 @@
1
1
  require 'active_model'
2
2
 
3
3
  module Amorail
4
+ # Core class for all Amo entities (company, contact, etc)
4
5
  class AmoEntity
5
6
  include ActiveModel::Model
6
7
  include ActiveModel::AttributeMethods
7
8
  include ActiveModel::Validations
8
9
 
9
- class InvalidRecord < ::Amorail::Error; end
10
- class NotPersisted < ::Amorail::Error; end
11
10
  class RecordNotFound < ::Amorail::Error; end
12
11
 
13
12
  class << self
14
- attr_reader :amo_name, :amo_response_name, :attributes, :properties
13
+ attr_reader :amo_name, :amo_response_name
15
14
 
16
15
  def amo_names(name, response_name = nil)
17
16
  @amo_name = @amo_response_name = name
@@ -19,26 +18,23 @@ module Amorail
19
18
  end
20
19
 
21
20
  def amo_field(*vars, **hargs)
22
- @attributes ||= {}
23
- vars.each { |v| @attributes[v] = :default }
24
- hargs.each { |k, v| @attributes[k] = v }
25
- attr_accessor(*@attributes.keys)
21
+ vars.each { |v| attributes[v] = :default }
22
+ hargs.each { |k, v| attributes[k] = v }
23
+ attr_accessor(*(vars + hargs.keys))
26
24
  end
27
25
 
28
26
  def amo_property(name, options = {})
29
- @properties ||= {}
30
- @properties[name] = options
27
+ properties[name] = options
31
28
  attr_accessor(name)
32
29
  end
33
30
 
34
- def find(id)
35
- new.load_record(id)
31
+ def attributes
32
+ @attributes ||=
33
+ superclass.respond_to?(:attributes) ? superclass.attributes.dup : {}
36
34
  end
37
35
 
38
- def find!(id)
39
- rec = find(id)
40
- fail RecordNotFound unless rec
41
- rec
36
+ def properties
37
+ @properties ||= {}
42
38
  end
43
39
  end
44
40
 
@@ -48,145 +44,16 @@ module Amorail
48
44
  date_create: :timestamp, last_modified: :timestamp
49
45
 
50
46
  delegate :client, :properties, to: Amorail
47
+ delegate :amo_name, to: :class
51
48
 
52
49
  def initialize(attributes = {})
53
50
  super(attributes)
54
51
  self.last_modified = Time.now.to_i if last_modified.nil?
55
52
  end
56
53
 
57
- def new_record?
58
- id.blank?
59
- end
60
-
61
- def persisted?
62
- !new_record?
63
- end
64
-
65
- def load_record(id)
66
- response = client.safe_request(
67
- :get,
68
- remote_url('list'),
69
- id: id
70
- )
71
- handle_response(response, 'load')
72
- end
73
-
74
- def save
75
- return false unless valid?
76
- new_record? ? push('add') : push('update')
77
- end
78
-
79
- def save!
80
- if save
81
- true
82
- else
83
- fail InvalidRecord
84
- end
85
- end
86
-
87
- def update(attrs = {})
88
- return false if new_record?
89
- merge_params(attrs)
90
- push('update')
91
- end
92
-
93
- def update!(attrs = {})
94
- if update(attrs)
95
- true
96
- else
97
- fail NotPersisted
98
- end
99
- end
100
-
101
- def params
102
- data = {}
103
- self.class.attributes.each do |k, v|
104
- data[k] = send("to_#{v}", send(k))
105
- end
106
-
107
- data[:custom_fields] = custom_fields
108
-
109
- normalize_params(data)
110
- end
111
-
112
- protected
113
-
114
- def custom_fields
115
- return unless properties.respond_to?(self.class.amo_name)
116
-
117
- return if self.class.properties.nil?
118
-
119
- props = properties.send(self.class.amo_name)
120
-
121
- custom_fields = []
122
-
123
- self.class.properties.each do |k, v|
124
- prop_id = props.send(k).id
125
- prop_val = { value: send(k) }.merge(v)
126
- custom_fields << { id: prop_id, values: [prop_val] }
127
- end
128
-
129
- custom_fields
130
- end
131
-
132
- def create_params(method)
133
- {
134
- request: {
135
- self.class.amo_response_name => {
136
- method => [
137
- params
138
- ]
139
- }
140
- }
141
- }
142
- end
143
-
144
- def normalize_custom_fields(val)
145
- val.reject do |field|
146
- field[:values].all? { |item| !item[:value] }
147
- end
148
- end
149
-
150
- # this method removes nil values and empty arrays from params hash (deep)
151
- def normalize_params(data)
152
- return data unless data.is_a?(Hash)
153
-
154
- compacted = {}
155
- data.each do |key, val|
156
- case val
157
- when Numeric, String
158
- compacted[key] = val
159
- when Array
160
- val.compact!
161
- # handle custom keys
162
- val = normalize_custom_fields(val) if key == :custom_fields
163
- unless val.empty?
164
- compacted[key] = val.map { |el| normalize_params(el) }
165
- end
166
- else
167
- params = normalize_params(val)
168
- compacted[key] = params unless params.nil?
169
- end
170
- end
171
- compacted.with_indifferent_access
172
- end
173
-
174
- def to_timestamp(val)
175
- return if val.nil?
176
-
177
- case val
178
- when String
179
- (date = Time.parse(val)) && date.to_i
180
- when Date
181
- val.to_time.to_i
182
- else
183
- val.to_i
184
- end
185
- end
186
-
187
- def to_default(val)
188
- val
189
- end
54
+ require 'amorail/entity/params'
55
+ require 'amorail/entity/persistance'
56
+ require 'amorail/entity/finders'
190
57
 
191
58
  def reload_model(info)
192
59
  merge_params(info)
@@ -214,10 +81,6 @@ module Amorail
214
81
  end
215
82
  end
216
83
 
217
- def attributes_list
218
- self.class.attributes
219
- end
220
-
221
84
  def remote_url(action)
222
85
  File.join(Amorail.config.api_path, self.class.amo_name, action)
223
86
  end
@@ -238,26 +101,14 @@ module Amorail
238
101
  end
239
102
 
240
103
  def handle_response(response, method)
241
- if response.status == 200
242
- extract_method = "extract_data_#{method}"
243
- reload_model(
244
- send(
245
- extract_method,
246
- response.body['response'][self.class.amo_response_name]
247
- )
248
- ) if respond_to?(extract_method, true)
249
- self
250
- else
251
- false
252
- end
253
- end
254
-
255
- def extract_data_load(response)
256
- response.first
257
- end
258
-
259
- def extract_data_add(response)
260
- response.fetch('add').first
104
+ return false unless response.status == 200
105
+ extract_method = "extract_data_#{method}"
106
+ reload_model(
107
+ send(extract_method,
108
+ response.body['response'][self.class.amo_response_name]
109
+ )
110
+ ) if respond_to?(extract_method, true)
111
+ self
261
112
  end
262
113
  end
263
114
  end