machineshop 0.0.1

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.
Files changed (58) 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 +8 -0
  16. data/LICENSE +22 -0
  17. data/README.md +29 -0
  18. data/Rakefile +8 -0
  19. data/doc.txt +50 -0
  20. data/lib/machineshop.rb +234 -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 +17 -0
  25. data/lib/machineshop/api_resource.rb +35 -0
  26. data/lib/machineshop/configuration.rb +11 -0
  27. data/lib/machineshop/customer.rb +9 -0
  28. data/lib/machineshop/database.rb +112 -0
  29. data/lib/machineshop/device.rb +30 -0
  30. data/lib/machineshop/device_instance.rb +30 -0
  31. data/lib/machineshop/errors/api_error.rb +4 -0
  32. data/lib/machineshop/errors/authentication_error.rb +4 -0
  33. data/lib/machineshop/errors/database_error.rb +5 -0
  34. data/lib/machineshop/errors/invalid_request_error.rb +10 -0
  35. data/lib/machineshop/errors/machineshop_error.rb +20 -0
  36. data/lib/machineshop/json.rb +21 -0
  37. data/lib/machineshop/machineshop_cache.rb +49 -0
  38. data/lib/machineshop/machineshop_object.rb +164 -0
  39. data/lib/machineshop/mapping.rb +34 -0
  40. data/lib/machineshop/meter.rb +12 -0
  41. data/lib/machineshop/models/people.rb +11 -0
  42. data/lib/machineshop/report.rb +11 -0
  43. data/lib/machineshop/rule.rb +58 -0
  44. data/lib/machineshop/user.rb +43 -0
  45. data/lib/machineshop/util.rb +115 -0
  46. data/lib/machineshop/utility.rb +30 -0
  47. data/lib/machineshop/version.rb +3 -0
  48. data/machineshop.gemspec +24 -0
  49. data/spec/lib/api_calls_spec.rb +628 -0
  50. data/spec/lib/customer_spec.rb +76 -0
  51. data/spec/lib/device_spec.rb +179 -0
  52. data/spec/lib/mapping_spec.rb +64 -0
  53. data/spec/lib/meter_spec.rb +46 -0
  54. data/spec/lib/report_spec.rb +52 -0
  55. data/spec/lib/rule_spec.rb +117 -0
  56. data/spec/lib/user_spec.rb +53 -0
  57. data/spec/spec_helper.rb +3 -0
  58. metadata +184 -0
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in machineshop.gemspec
4
+ gemspec
5
+
6
+ gem "mysql"
7
+ gem "activerecord"
8
+ gem "awesome_print"
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 John Cox
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # MachineShop
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'machineshop'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install machineshop
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
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,234 @@
1
+ require "machineshop/version"
2
+
3
+ require 'cgi'
4
+ require 'set'
5
+ require 'openssl'
6
+ require 'rest_client'
7
+ require "base64"
8
+ require 'rest_client'
9
+ require "addressable/uri"
10
+ require 'multi_json'
11
+
12
+ #configurations
13
+ require 'machineshop/configuration'
14
+ #database
15
+ # require 'machineshop/database'
16
+
17
+ # API operations
18
+ require 'machineshop/api_operations/create'
19
+ require 'machineshop/api_operations/delete'
20
+ require 'machineshop/api_operations/list'
21
+ require 'machineshop/api_operations/update'
22
+
23
+ # Resources
24
+
25
+ require 'machineshop/machineshop_object'
26
+ require 'machineshop/api_resource'
27
+ require 'machineshop/device_instance'
28
+ require 'machineshop/device'
29
+ require 'machineshop/machineshop_object'
30
+ require 'machineshop/mapping'
31
+ require 'machineshop/meter'
32
+ require 'machineshop/report'
33
+ require 'machineshop/customer'
34
+ require 'machineshop/rule'
35
+ require 'machineshop/user'
36
+ require 'machineshop/utility'
37
+ require 'machineshop/json'
38
+ require 'machineshop/util'
39
+
40
+ # Errors
41
+ require 'machineshop/errors/machineshop_error'
42
+ require 'machineshop/errors/api_error'
43
+ require 'machineshop/errors/invalid_request_error'
44
+ require 'machineshop/errors/authentication_error'
45
+
46
+ # require 'machineshop/models/people'
47
+
48
+
49
+ module MachineShop
50
+ class << self
51
+ # @@api_base_url = 'http://api.machineshop.io/api/v0'
52
+ @@api_base_url = 'http://stage.services.machineshop.io/api/v0'
53
+
54
+ #configs starts
55
+ attr_writer :configuration
56
+
57
+ def configuration
58
+ @configuration ||= Configuration.new
59
+ end
60
+
61
+ def configure
62
+ yield(configuration)
63
+ end
64
+
65
+ #reset the config object
66
+ def reset
67
+ Configuration.new
68
+ end
69
+
70
+ #configs ends
71
+
72
+ def api_base_url=(api_base_url)
73
+ @@api_base_url = api_base_url
74
+ end
75
+
76
+ def api_base_url
77
+ @@api_base_url
78
+ end
79
+
80
+ def get(url, auth_token, body_hash=nil)
81
+ platform_request(url, auth_token, body_hash)
82
+ end
83
+
84
+ def post(url, auth_token, body_hash)
85
+ platform_request(url, auth_token, body_hash, :post)
86
+ end
87
+
88
+ def delete(url, auth_token, body_hash)
89
+ platform_request(url, auth_token, body_hash, :delete)
90
+ end
91
+
92
+ def put(url, auth_token, body_hash)
93
+ platform_request(url, auth_token, body_hash, :put)
94
+ end
95
+
96
+ def headers(auth_token)
97
+ header ={:content_type => :json,
98
+ :accept => :json}
99
+ header.merge!({ authorization: "Basic " + Base64.encode64(auth_token + ':X') }) if auth_token
100
+ header
101
+ end
102
+
103
+ def platform_request(url, auth_token, body_hash=nil, http_verb=:get )
104
+ puts "body_hash: #{body_hash}"
105
+ opts = nil
106
+ api_uri = api_base_url + url
107
+ headers = self.headers(auth_token)
108
+ if http_verb == :get
109
+ if (body_hash && !body_hash.empty?)
110
+ uri = Addressable::URI.new
111
+ uri.query_values = body_hash
112
+ api_uri += "?" + uri.query
113
+ end
114
+
115
+ opts = {
116
+ :method => :get,
117
+ :url => api_uri,
118
+ :headers => headers,
119
+ :open_timeout => 30,
120
+ :timeout => 80
121
+ }
122
+
123
+ else
124
+ opts = {
125
+ :method => http_verb,
126
+ :url => api_uri,
127
+ :headers => headers,
128
+ :open_timeout => 30,
129
+ :payload => MachineShop::JSON.dump(body_hash),
130
+ :timeout => 80
131
+ }
132
+
133
+ end
134
+
135
+ puts "request params: #{opts} "
136
+
137
+ begin
138
+ response = execute_request(opts)
139
+ rescue SocketError => e
140
+ self.handle_restclient_error(e)
141
+ rescue NoMethodError => e
142
+ # Work around RestClient bug
143
+ if e.message =~ /\WRequestFailed\W/
144
+ e = APIConnectionError.new('Unexpected HTTP response code')
145
+ self.handle_restclient_error(e)
146
+ else
147
+ raise
148
+ end
149
+ rescue RestClient::ExceptionWithResponse => e
150
+ if rcode = e.http_code and rbody = e.http_body
151
+ self.handle_api_error(rcode, rbody)
152
+ else
153
+ self.handle_restclient_error(e)
154
+ end
155
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
156
+ self.handle_restclient_error(e)
157
+ end
158
+
159
+ rbody = response.body
160
+ rcode = response.code
161
+
162
+ begin
163
+ # Would use :symbolize_names => true, but apparently there is
164
+ # some library out there that makes symbolize_names not work.
165
+ resp = MachineShop::JSON.load(rbody)
166
+ resp ||= {}
167
+ resp = Util.symbolize_names(resp)
168
+
169
+ resp.merge!({:http_code => rcode}) if resp.is_a?(Hash)
170
+ return resp
171
+ rescue MultiJson::DecodeError
172
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
173
+ end
174
+
175
+ end
176
+
177
+
178
+ def execute_request(opts)
179
+ RestClient::Request.execute(opts)
180
+ end
181
+
182
+ def handle_api_error(rcode, rbody)
183
+ begin
184
+ error_obj = MachineShop::JSON.load(rbody)
185
+ error_obj = Util.symbolize_names(error_obj)
186
+ error = error_obj[:error] or raise MachineShopError.new # escape from parsing
187
+ rescue MultiJson::DecodeError, MachineShopError
188
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
189
+ end
190
+
191
+ case rcode
192
+ when 400, 404 then
193
+ raise invalid_request_error(error, rcode, rbody, error_obj)
194
+ when 401
195
+ raise authentication_error(error, rcode, rbody, error_obj)
196
+ when 402
197
+ # TODO Come up with errors
198
+ else
199
+ raise api_error(error, rcode, rbody, error_obj)
200
+ end
201
+ end
202
+
203
+ def invalid_request_error(error, rcode, rbody, error_obj)
204
+ InvalidRequestError.new(error, error, rcode, rbody, error_obj)
205
+ end
206
+
207
+ def authentication_error(error, rcode, rbody, error_obj)
208
+ AuthenticationError.new(error, rcode, rbody, error_obj)
209
+ end
210
+
211
+ def api_error(error, rcode, rbody, error_obj)
212
+ APIError.new(error, rcode, rbody, error_obj)
213
+ end
214
+
215
+ def handle_restclient_error(e)
216
+ case e
217
+ when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
218
+ 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."
219
+ when RestClient::SSLCertificateNotVerified
220
+ message = "Could not verify MachineShops's SSL certificate. Please make sure that your network is not intercepting certificates."
221
+ when SocketError
222
+ 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."
223
+ else
224
+ message = "Unexpected error communicating with MachineShop"
225
+ end
226
+ message += "\n\n(Network error: #{e.message})"
227
+ # puts "error message string : #{message}"
228
+ raise APIConnectionError.new(message)
229
+ end
230
+
231
+
232
+
233
+ end
234
+ end
@@ -0,0 +1,17 @@
1
+ #Defining class method inside a module
2
+ module MachineShop
3
+ module APIOperations
4
+ module Create
5
+ module ClassMethods
6
+ def create(params={}, auth_token=nil)
7
+ response = MachineShop.post(self.url, auth_token, params)
8
+ Util.convert_to_machineshop_object(response, auth_token, self.class_name)
9
+ end
10
+ end
11
+
12
+ def self.included(base)
13
+ base.extend(ClassMethods)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module MachineShop
2
+ module APIOperations
3
+ module Delete
4
+ def delete
5
+ response = MachineShop.delete(url, @auth_token,{})
6
+ refresh_from(response, @auth_token)
7
+ self
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module MachineShop
2
+ module APIOperations
3
+ module List
4
+ module ClassMethods
5
+ def all(filters={}, auth_token=nil)
6
+ response = MachineShop.get(url, auth_token, filters)
7
+ Util.convert_to_machineshop_object(response, auth_token, self.class_name)
8
+ end
9
+ end
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ #Defining class method inside a module
2
+ module MachineShop
3
+ module APIOperations
4
+ module Update
5
+ module ClassMethods
6
+ def update(id,auth_token,params={})
7
+ response = MachineShop.put(self.url+"/#{id}", auth_token, params)
8
+ Util.convert_to_machineshop_object(response, auth_token, self.class_name)
9
+ end
10
+ end
11
+
12
+ def self.included(base)
13
+ base.extend(ClassMethods)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ module MachineShop
2
+ class APIResource < MachineShopObject
3
+ def self.class_name
4
+ self.name.split('::')[-1]
5
+ end
6
+
7
+ def self.url()
8
+ if self == APIResource
9
+ raise NotImplementedError.new('APIResource is an abstract class. You should perform actions on its subclasses (Device, Rule, etc.)')
10
+ end
11
+ ret = "/platform/#{CGI.escape(class_name.underscore)}"
12
+ ret
13
+ end
14
+
15
+ def url
16
+ unless id = self['id']
17
+ raise InvalidRequestError.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}", 'id')
18
+ end
19
+ ret = "#{self.class.url}/#{CGI.escape(id)}"
20
+ ret
21
+ end
22
+
23
+ def refresh
24
+ response = MachineShop.get(url, @auth_token)
25
+ refresh_from(response, auth_token)
26
+ self
27
+ end
28
+
29
+ def self.retrieve(id, auth_token=nil)
30
+ instance = self.new(id, auth_token)
31
+ instance.refresh
32
+ instance
33
+ end
34
+ end
35
+ end