test_machine_shop 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.idea/.name +1 -0
  3. data/.idea/.rakeTasks +7 -0
  4. data/.idea/compiler.xml +23 -0
  5. data/.idea/copyright/profiles_settings.xml +5 -0
  6. data/.idea/encodings.xml +5 -0
  7. data/.idea/inspectionProfiles/Project_Default.xml +7 -0
  8. data/.idea/inspectionProfiles/profiles_settings.xml +7 -0
  9. data/.idea/machineshop.iml +194 -0
  10. data/.idea/misc.xml +5 -0
  11. data/.idea/modules.xml +9 -0
  12. data/.idea/scopes/scope_settings.xml +5 -0
  13. data/.idea/vcs.xml +7 -0
  14. data/.idea/workspace.xml +722 -0
  15. data/Gemfile +9 -0
  16. data/LICENSE +22 -0
  17. data/README.md +977 -0
  18. data/Rakefile +8 -0
  19. data/doc.txt +50 -0
  20. data/lib/machineshop.rb +475 -0
  21. data/lib/machineshop/api_operations/create.rb +17 -0
  22. data/lib/machineshop/api_operations/delete.rb +11 -0
  23. data/lib/machineshop/api_operations/list.rb +16 -0
  24. data/lib/machineshop/api_operations/update.rb +11 -0
  25. data/lib/machineshop/api_resource.rb +35 -0
  26. data/lib/machineshop/configuration.rb +14 -0
  27. data/lib/machineshop/customer.rb +15 -0
  28. data/lib/machineshop/data_source_types.rb +28 -0
  29. data/lib/machineshop/data_sources.rb +35 -0
  30. data/lib/machineshop/database.rb +59 -0
  31. data/lib/machineshop/device.rb +30 -0
  32. data/lib/machineshop/device_instance.rb +30 -0
  33. data/lib/machineshop/end_points.rb +30 -0
  34. data/lib/machineshop/errors/api_connection_error.rb +4 -0
  35. data/lib/machineshop/errors/api_error.rb +4 -0
  36. data/lib/machineshop/errors/authentication_error.rb +4 -0
  37. data/lib/machineshop/errors/database_error.rb +5 -0
  38. data/lib/machineshop/errors/invalid_request_error.rb +10 -0
  39. data/lib/machineshop/errors/machineshop_error.rb +20 -0
  40. data/lib/machineshop/errors/schema_error.rb +5 -0
  41. data/lib/machineshop/json.rb +21 -0
  42. data/lib/machineshop/machineshop_cache.rb +49 -0
  43. data/lib/machineshop/machineshop_object.rb +165 -0
  44. data/lib/machineshop/mapping.rb +34 -0
  45. data/lib/machineshop/meter.rb +12 -0
  46. data/lib/machineshop/models/api_endpoint.rb +8 -0
  47. data/lib/machineshop/models/api_request.rb +28 -0
  48. data/lib/machineshop/models/schema.rb +184 -0
  49. data/lib/machineshop/report.rb +11 -0
  50. data/lib/machineshop/rule.rb +42 -0
  51. data/lib/machineshop/user.rb +43 -0
  52. data/lib/machineshop/users.rb +43 -0
  53. data/lib/machineshop/util.rb +193 -0
  54. data/lib/machineshop/utility.rb +30 -0
  55. data/lib/machineshop/version.rb +3 -0
  56. data/machineshop.gemspec +35 -0
  57. data/spec/lib/api_calls_spec.rb +628 -0
  58. data/spec/lib/custom_endpoint_test.rb +78 -0
  59. data/spec/lib/customer_spec.rb +87 -0
  60. data/spec/lib/data_source.rb +138 -0
  61. data/spec/lib/data_source_type_spec.rb +77 -0
  62. data/spec/lib/database_spec.rb +45 -0
  63. data/spec/lib/device_instances.rb +73 -0
  64. data/spec/lib/device_spec.rb +172 -0
  65. data/spec/lib/endpoint_spec.rb +37 -0
  66. data/spec/lib/geocode_spec +45 -0
  67. data/spec/lib/mapping_spec.rb +68 -0
  68. data/spec/lib/meter_spec.rb +49 -0
  69. data/spec/lib/report_spec.rb +52 -0
  70. data/spec/lib/rule_spec.rb +130 -0
  71. data/spec/lib/user_spec.rb +58 -0
  72. data/spec/spec_helper.rb +12 -0
  73. metadata +235 -0
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new
6
+
7
+ task :default => :spec
8
+ task :test => :spec
data/doc.txt ADDED
@@ -0,0 +1,50 @@
1
+ #response from authenticate
2
+
3
+ {:_id=>"52160c8e981800aaef000001",
4
+ :authentication_token=>"2jzZmcHWLZyghsxcB16E",
5
+ :company_name=>"CSR",
6
+ :current_sign_in_at=>"2014-03-21T09:32:13Z",
7
+ :current_sign_in_ip=>"202.51.76.235",
8
+ :email=>"admin@csr.com",
9
+ :first_name=>"CSR",
10
+ :keychain=>{},
11
+ :last_name=>"Admin",
12
+ :last_sign_in_at=>"2014-03-21T09:11:08Z",
13
+ :last_sign_in_ip=>"202.51.76.235",
14
+ :logo_url=>nil,
15
+ :notification_method=>"sms",
16
+ :phone_number=>"+1 (123) 456-7890",
17
+ :role=>"admin",
18
+ :sign_in_count=>7910,
19
+ :tag_ids=>[],
20
+ :http_code=>200}
21
+
22
+
23
+
24
+ #user object
25
+
26
+ {
27
+ "id": "52160c8e981800aaef000001",
28
+ "_id": "52160c8e981800aaef000001",
29
+ "authentication_token": "2jzZmcHWLZyghsxcB16E",
30
+ "company_name": "CSR",
31
+ "current_sign_in_at": "2014-03-21T09:30:42Z",
32
+ "current_sign_in_ip": "202.51.76.235",
33
+ "email": "admin@csr.com",
34
+ "first_name": "CSR",
35
+ "keychain": {},
36
+ "last_name": "Admin",
37
+ "last_sign_in_at": "2014-03-21T09:32:13Z",
38
+ "last_sign_in_ip": "202.51.76.235",
39
+ "logo_url": null,
40
+ "notification_method": "sms",
41
+ "phone_number": "+1 (123) 456-7890",
42
+ "role": "admin",
43
+ "sign_in_count": 7912,
44
+ "tag_ids": [
45
+
46
+ ],
47
+ "http_code": 200
48
+ }
49
+
50
+
@@ -0,0 +1,475 @@
1
+ require "machineshop/version"
2
+
3
+ # require 'awesome_print'
4
+ # require 'will_paginate'
5
+
6
+ require 'cgi'
7
+ require 'set'
8
+ require 'openssl'
9
+ require 'rest_client'
10
+ require "base64"
11
+ require "addressable/uri"
12
+ require 'multi_json'
13
+
14
+ #configurations
15
+ require 'machineshop/configuration'
16
+ #database
17
+ require 'machineshop/database'
18
+
19
+ # API operations
20
+ require 'machineshop/api_operations/create'
21
+ require 'machineshop/api_operations/delete'
22
+ require 'machineshop/api_operations/list'
23
+ require 'machineshop/api_operations/update'
24
+
25
+ # Resources
26
+
27
+ require 'machineshop/machineshop_object'
28
+ require 'machineshop/api_resource'
29
+ require 'machineshop/device_instance'
30
+ require 'machineshop/device'
31
+ require 'machineshop/machineshop_object'
32
+ require 'machineshop/mapping'
33
+ require 'machineshop/meter'
34
+ require 'machineshop/report'
35
+ require 'machineshop/customer'
36
+ require 'machineshop/rule'
37
+ # require 'machineshop/user'
38
+ require 'machineshop/users'
39
+ require 'machineshop/utility'
40
+ require 'machineshop/json'
41
+ require 'machineshop/util'
42
+ require 'machineshop/end_points'
43
+
44
+ require 'machineshop/data_sources'
45
+ require 'machineshop/data_source_types'
46
+
47
+ # Errors
48
+ require 'machineshop/errors/machineshop_error'
49
+ require 'machineshop/errors/api_error'
50
+ require 'machineshop/errors/invalid_request_error'
51
+ require 'machineshop/errors/authentication_error'
52
+ require 'machineshop/errors/api_connection_error'
53
+
54
+ #Models
55
+ require 'machineshop/models/api_request'
56
+ require 'machineshop/models/api_endpoint'
57
+
58
+
59
+ module MachineShop
60
+ class << self
61
+ # @@api_base_url = 'http://api.machineshop.io/api/v0'
62
+ @@api_base_url = 'http://stage.services.machineshop.io/api/v0'
63
+
64
+ #configs starts
65
+ attr_writer :configuration
66
+
67
+ def configuration
68
+ @configuration ||= Configuration.new
69
+ end
70
+
71
+ def configure
72
+ yield(configuration)
73
+ end
74
+
75
+ #reset the config object
76
+ def reset
77
+ Configuration.new
78
+ end
79
+
80
+ #configs ends
81
+
82
+ def api_base_url=(api_base_url)
83
+ @@api_base_url = api_base_url
84
+ end
85
+
86
+ def api_base_url
87
+ @@api_base_url
88
+ end
89
+
90
+ #For Custom endpoints
91
+ def get(name, auth_token, *params)
92
+ url = Util.valid_endpoint(name,auth_token,:get, params)
93
+ platform_request(url, auth_token, nil, :get)
94
+ end
95
+
96
+ def post(name,auth_token, body_hash)
97
+ url = Util.valid_endpoint(name,auth_token,:post,[])
98
+ platform_request(url, auth_token,body_hash,:post)
99
+ end
100
+
101
+ def put(name,auth_token,*params,body_hash)
102
+ url = Util.valid_endpoint(name,auth_token,:put,params)
103
+ platform_request(url, auth_token,body_hash,:put)
104
+ end
105
+
106
+ def delete(name,auth_token,*params)
107
+ url = Util.valid_endpoint(name,auth_token,:delete,params)
108
+ platform_request(url, auth_token, nil ,:delete)
109
+ end
110
+
111
+ #Call for the predefined request
112
+ def gem_get(url, auth_token, body_hash=nil)
113
+ platform_request(url, auth_token, body_hash)
114
+ end
115
+
116
+ def gem_post(url, auth_token, body_hash)
117
+ platform_request(url, auth_token, body_hash, :post)
118
+ end
119
+
120
+ def gem_delete(url, auth_token, body_hash)
121
+ platform_request(url, auth_token, body_hash, :delete)
122
+ end
123
+
124
+ def gem_put(url, auth_token, body_hash)
125
+ platform_request(url, auth_token, body_hash, :put)
126
+ end
127
+
128
+ def headers(auth_token)
129
+ header ={:content_type => :json,
130
+ :accept => :json}
131
+ header.merge!({ authorization: "Basic " + Base64.encode64(auth_token + ':X') }) if auth_token
132
+ header
133
+ end
134
+
135
+ def platform_request(url, auth_token, body_hash=nil, http_verb=:get )
136
+ rbody=nil
137
+ cachedContent = :true
138
+ # ApiRequest.cache(url,MachineShop.configuration.expiry_time)
139
+ if http_verb==:get
140
+
141
+ if Util.db_connected?
142
+ xpired=true
143
+
144
+ ApiRequest.cache(url, auth_token, MachineShop.configuration.expiry_time) do
145
+ xpired=false
146
+ puts "Not expired , calling from local "
147
+ rbody = get_from_cache(url,body_hash,auth_token)
148
+ rcode="200"
149
+ end
150
+ end
151
+
152
+ end
153
+ if (rbody.nil? || rbody.empty?)
154
+ cachedContent=:false
155
+ opts = nil
156
+ api_uri = api_base_url + url
157
+ headers = self.headers(auth_token)
158
+ if http_verb == :get
159
+ if (body_hash && !body_hash.empty?)
160
+ uri = Addressable::URI.new
161
+ uri.query_values = body_hash
162
+ api_uri += "?" + uri.query
163
+ end
164
+
165
+ opts = {
166
+ :method => :get,
167
+ :url => api_uri,
168
+ :headers => headers,
169
+ :open_timeout => 30,
170
+ :timeout => 80
171
+ }
172
+
173
+ else
174
+ opts = {
175
+ :method => http_verb,
176
+ :url => api_uri,
177
+ :headers => headers,
178
+ :open_timeout => 30,
179
+ :payload => MachineShop::JSON.dump(body_hash),
180
+ :timeout => 80
181
+ }
182
+
183
+ end
184
+
185
+ puts "request params: #{opts} "
186
+
187
+ begin
188
+ response = execute_request(opts)
189
+
190
+ rescue SocketError => e
191
+ self.handle_restclient_error(e)
192
+ rescue NoMethodError => e
193
+ # Work around RestClient bug
194
+ if e.message =~ /\WRequestFailed\W/
195
+ e = APIConnectionError.new('Unexpected HTTP response code')
196
+ self.handle_restclient_error(e)
197
+ else
198
+ raise
199
+ end
200
+ rescue RestClient::ExceptionWithResponse => e
201
+ if rcode = e.http_code and rbody = e.http_body
202
+ self.handle_api_error(rcode, rbody)
203
+ else
204
+ self.handle_restclient_error(e)
205
+ end
206
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
207
+ self.handle_restclient_error(e)
208
+ end
209
+
210
+ rbody = response.body
211
+ # puts rbody
212
+ rcode = response.code
213
+ end
214
+
215
+ begin
216
+ # Would use :symbolize_names => true, but apparently there is
217
+ # some library out there that makes symbolize_names not work.
218
+ resp = MachineShop::JSON.load(rbody)
219
+ resp ||= {}
220
+ resp = Util.symbolize_names(resp)
221
+
222
+ save_into_cache(url,resp,auth_token) if (http_verb == :get && cachedContent==:false)
223
+
224
+ resp.merge!({:http_code => rcode}) if resp.is_a?(Hash)
225
+ return resp
226
+ rescue MultiJson::DecodeError
227
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
228
+ end
229
+
230
+ end
231
+
232
+
233
+ def execute_request(opts)
234
+ RestClient::Request.execute(opts)
235
+ end
236
+
237
+ def handle_api_error(rcode, rbody)
238
+ begin
239
+ error_obj = MachineShop::JSON.load(rbody)
240
+ error_obj = Util.symbolize_names(error_obj)
241
+ error = error_obj[:error] or raise MachineShopError.new # escape from parsing
242
+ rescue MultiJson::DecodeError, MachineShopError
243
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
244
+ end
245
+
246
+ case rcode
247
+ when 400, 404 then
248
+ raise invalid_request_error(error, rcode, rbody, error_obj)
249
+ when 401
250
+ raise authentication_error(error, rcode, rbody, error_obj)
251
+ when 402
252
+ # TODO Come up with errors
253
+ else
254
+ raise api_error(error, rcode, rbody, error_obj)
255
+ end
256
+ end
257
+
258
+ def invalid_request_error(error, rcode, rbody, error_obj)
259
+ InvalidRequestError.new(error, error, rcode, rbody, error_obj)
260
+ end
261
+
262
+ def authentication_error(error, rcode, rbody, error_obj)
263
+ AuthenticationError.new(error, rcode, rbody, error_obj)
264
+ end
265
+
266
+ def api_error(error, rcode, rbody, error_obj)
267
+ APIError.new(error, rcode, rbody, error_obj)
268
+ end
269
+
270
+ def handle_restclient_error(e)
271
+ case e
272
+ when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
273
+ message = "Could not connect to MachineShop (#{@@api_base_url}). Please check your internet connection and try again. If this problem persists, you should check MachineShop's service status."
274
+ when RestClient::SSLCertificateNotVerified
275
+ message = "Could not verify MachineShops's SSL certificate. Please make sure that your network is not intercepting certificates."
276
+ when SocketError
277
+ message = "Unexpected error communicating when trying to connect to MachineShop (#{@@api_base_url}). HINT: You may be seeing this message because your DNS is not working."
278
+ else
279
+ message = "Unexpected error communicating with MachineShop"
280
+ end
281
+ message += "\n\n(Network error: #{e.message})"
282
+ # puts "error message string : #{message}"
283
+ raise APIConnectionError.new(message)
284
+ end
285
+
286
+
287
+ # Check if the class with the variable exists
288
+ def class_exists?(class_name)
289
+ klass = class_name.constantize
290
+ return klass.is_a?(Class)
291
+ rescue NameError =>e
292
+ return false
293
+ end
294
+
295
+
296
+ def save_into_cache(url, data,auth_token)
297
+ id,klass= Util.get_klass_from_url(url)
298
+ if !TABLE_NAME_BLACKLIST.include?(klass)
299
+ if Util.db_connected?
300
+
301
+ klass = klass.capitalize+"Cache"
302
+ puts "creating dynamic class #{klass}"
303
+
304
+
305
+ modelClass ||= (Object.const_set klass, Class.new(ActiveRecord::Base))
306
+ modelClass.inheritance_column = :_type_disabled
307
+ #Because 'type' is reserved for storing the class in case of inheritance and our array has "TYPE" key
308
+
309
+ if ActiveRecord::Base.connection.table_exists? CGI.escape(klass.pluralize.underscore)
310
+
311
+ #delete all the previous records
312
+
313
+ modelClass.delete_all
314
+ puts "db table #{klass.pluralize.underscore} exists"
315
+ if data.class ==Hash
316
+
317
+ findId = data[:_id] || data["_id"]
318
+ @activeObject = modelClass.new
319
+ # @activeObject = modelClass.find_by(_id: findId) || modelClass.new
320
+ data.each do |k,v|
321
+
322
+ val=nil
323
+
324
+ if v.class==Array
325
+ val = v.to_json
326
+ elsif v.class==Hash
327
+ val = v.to_json
328
+ else
329
+ val=v
330
+ end
331
+ if @activeObject.has_attribute?(k)
332
+ @activeObject.send("#{k}=",val)
333
+ end
334
+ @activeObject.save
335
+ end
336
+
337
+
338
+ else
339
+ data.each do |data_arr|
340
+
341
+ if data_arr
342
+
343
+ if data_arr.first.class==String && data_arr.class==Array
344
+ @activeObject = modelClass.find_by(rule_condition: data_arr.select{|k| k.include?("rule_condition")}) || modelClass.new
345
+ data_arr.each do |k|
346
+
347
+ if k.include?("rule_condition")
348
+ @activeObject.rule_condition = k
349
+ else
350
+ @activeObject.rule_description=k
351
+ end
352
+ end
353
+
354
+
355
+ else
356
+ if data_arr.class!=String
357
+ findId = data_arr[:_id] || data_arr["_id"]
358
+ @activeObject = modelClass.find_by(_id: findId) || modelClass.new
359
+ data_arr.each do |k,v|
360
+
361
+ val=nil
362
+
363
+ if v.class==Array
364
+ val = v.to_json
365
+ elsif v.class==Hash
366
+ val = v.to_json
367
+ else
368
+ val=v
369
+ end
370
+ #check if the database has the particular field to store
371
+ if @activeObject.has_attribute?(k)
372
+ @activeObject.send("#{k}=",val)
373
+ end
374
+ end
375
+ end
376
+ end
377
+ end
378
+ @activeObject.send("auth_token=",auth_token)
379
+ @activeObject.save
380
+ end
381
+ end
382
+
383
+ end #if ActiveRecord ends
384
+
385
+ end #if db_connected ends
386
+ end #if !TABLE_NAME_BLACKLIST.include? ends
387
+ end
388
+
389
+
390
+ def get_from_cache(url, body_hash,auth_token)
391
+ result =Array.new
392
+ id,klass= Util.get_klass_from_url(url)
393
+ if !TABLE_NAME_BLACKLIST.include?(klass)
394
+ if Util.db_connected?
395
+
396
+ klass = klass.capitalize+"Cache"
397
+
398
+ modelClass = Object.const_set klass, Class.new(ActiveRecord::Base)
399
+ modelClass.inheritance_column = :_type_disabled
400
+
401
+ data_exist=false
402
+ if ActiveRecord::Base.connection.table_exists? CGI.escape(klass.pluralize.underscore)
403
+ puts "db:table #{klass.pluralize} exists"
404
+ resp= nil
405
+ if id
406
+ resp = modelClass.find_by(_id: id, auth_token: auth_token)
407
+ data_exist=true if resp
408
+ else
409
+ # pagination = body_hash.select{|k| k==:per_page || k==:page} if body_hash
410
+ resp = modelClass.where(parse_query_string(body_hash,auth_token))
411
+ data_exist = true if resp.exists?
412
+ end
413
+
414
+ if data_exist
415
+ if(klass.include?("rule_condition"))
416
+ resp.each do |rTemp|
417
+ temp = Array.new
418
+ temp.push rTemp["rule_description"]
419
+ temp.push rTemp["rule_condition"]
420
+ result << temp
421
+ end
422
+ result = result.to_json(:except=>[:id]) if result
423
+ else
424
+ result = resp.to_json(:except=>[:id]) if resp
425
+ end
426
+
427
+ end
428
+ end
429
+ end
430
+ end
431
+ return result
432
+ end
433
+
434
+ TABLE_NAME_BLACKLIST = ["user","routes"]
435
+ QUERY_STRING_BLACKLIST = [
436
+ 'page',
437
+ 'per_page'
438
+ ]
439
+
440
+ def parse_query_string(query_params,auth_token)
441
+
442
+ search_parms = {}
443
+ if query_params
444
+ params = Hash[query_params.map{ |k, v| [k.to_s, v] }]
445
+ operators = ["gt", "gte", "lt", "lte"]
446
+
447
+ xs = params.reject { |k,_| QUERY_STRING_BLACKLIST.include?(k) }
448
+ xs.each do |key,value|
449
+ tokens = key.split('_')
450
+ if tokens.nil? || tokens.length == 1
451
+ search_parms[key] = value
452
+ else
453
+ token_length = tokens[tokens.length-1].length-1
454
+ if operators.include?(tokens[tokens.length-1])
455
+ operator = "$" + tokens[tokens.length-1]
456
+ new_key = key[0,key.length-token_length-2].to_sym
457
+ search_parms[new_key] = { operator => value }
458
+ elsif tokens[tokens.length-1] == "between" && value.split("_").length > 1
459
+ new_key = key[0,key.length-token_length-2].to_sym
460
+ vals = value.split("_")
461
+ search_parms[new_key] = {"$gte" => vals[0], "$lte" => vals[1]}
462
+ else
463
+ search_parms[key] = value
464
+ end
465
+ end
466
+ end
467
+ end
468
+ #append auth_token = auth_token part as well
469
+ search_parms['auth_token']=auth_token
470
+ search_parms
471
+ end
472
+
473
+
474
+ end
475
+ end