amorail 0.1.4 → 0.1.5

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: 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