cs 0.1.1beta → 0.1.3
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 +4 -4
- data/.travis.yml +1 -2
- data/Gemfile +9 -1
- data/README.md +74 -0
- data/bin/cs +58 -0
- data/bin/cs-console +154 -0
- data/bin/cs-password +44 -0
- data/cs.gemspec +4 -1
- data/lib/cs.rb +31 -4
- data/lib/cs/auth/http.rb +23 -7
- data/lib/cs/cli/cli.rb +29 -0
- data/lib/cs/collection.rb +7 -0
- data/lib/cs/collection/sensor_data_collection.rb +62 -0
- data/lib/cs/end_point.rb +2 -0
- data/lib/cs/end_point/notification.rb +16 -0
- data/lib/cs/end_point/sensor.rb +31 -3
- data/lib/cs/end_point/sensor_data.rb +7 -2
- data/lib/cs/end_point/trigger.rb +16 -0
- data/lib/cs/relation.rb +2 -3
- data/lib/cs/relation/notification_relation.rb +20 -0
- data/lib/cs/relation/sensor_data_relation.rb +12 -0
- data/lib/cs/relation/sensor_relation.rb +27 -0
- data/lib/cs/relation/trigger_relation.rb +21 -0
- data/lib/cs/session.rb +29 -8
- data/lib/cs/version.rb +1 -1
- data/spec/features/user_management_spec.rb +2 -3
- data/spec/lib/cs/collection/sensor_data_collection_spec.rb +27 -0
- data/spec/lib/cs/end_point/sensor_spec.rb +28 -0
- data/spec/lib/cs/relation/group_relation_spec.rb +0 -9
- data/spec/lib/cs/relation/sensor_data_relation_spec.rb +0 -11
- data/spec/lib/cs/relation/sensor_relation_spec.rb +18 -9
- data/spec/lib/cs/session_spec.rb +16 -2
- data/spec/lib/cs_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +37 -8
data/lib/cs/auth/http.rb
CHANGED
@@ -7,10 +7,11 @@ module CS
|
|
7
7
|
include HTTParty
|
8
8
|
|
9
9
|
attr_accessor :response_body, :response_code, :response_headers, :errors
|
10
|
-
attr_reader :session_id
|
10
|
+
attr_reader :session_id, :api_key
|
11
11
|
|
12
|
-
def initialize(base_uri = nil)
|
12
|
+
def initialize(base_uri = nil, api_key = nil)
|
13
13
|
self.base_uri = base_uri
|
14
|
+
@api_key = api_key
|
14
15
|
@session_id = nil
|
15
16
|
reset
|
16
17
|
end
|
@@ -22,10 +23,23 @@ module CS
|
|
22
23
|
@response_body
|
23
24
|
end
|
24
25
|
|
26
|
+
def process_api_key(path)
|
27
|
+
return path if @api_key.nil?
|
28
|
+
|
29
|
+
if URI(path).query.nil?
|
30
|
+
path += "?API_KEY=#{@api_key}"
|
31
|
+
else
|
32
|
+
path += "&API_KEY=#{@api_key}"
|
33
|
+
end
|
34
|
+
|
35
|
+
path
|
36
|
+
end
|
37
|
+
|
25
38
|
def get(path, query={}, headers = {})
|
26
39
|
execute do
|
27
40
|
headers = default_headers.merge(headers)
|
28
41
|
options = {query: query, headers: headers}
|
42
|
+
path = process_api_key(path)
|
29
43
|
self.class.get(path, options)
|
30
44
|
end
|
31
45
|
end
|
@@ -66,7 +80,7 @@ module CS
|
|
66
80
|
header = self.class.default_options[:headers] || {}
|
67
81
|
header.merge!({"Content-Type" => "application/json"})
|
68
82
|
if @session_id
|
69
|
-
header.merge
|
83
|
+
header = header.merge('X-SESSION_ID' => self.session_id)
|
70
84
|
end
|
71
85
|
header
|
72
86
|
end
|
@@ -79,18 +93,19 @@ module CS
|
|
79
93
|
@session_id = session_id
|
80
94
|
end
|
81
95
|
|
82
|
-
|
83
96
|
# login to commonsense
|
84
97
|
# @return [String] session_id
|
85
|
-
def login(username, password)
|
86
|
-
|
98
|
+
def login(username, password, digest=true)
|
99
|
+
if digest
|
100
|
+
password = Digest::MD5.hexdigest password
|
101
|
+
end
|
87
102
|
post('/login.json', {:username => username, :password => password})
|
88
103
|
|
89
104
|
if @response_code == 200
|
90
105
|
self.session_id = response_body['session_id']
|
91
106
|
else
|
92
107
|
self.session_id = false
|
93
|
-
errors = [response_body['error']]
|
108
|
+
@errors = [response_body['error']]
|
94
109
|
end
|
95
110
|
|
96
111
|
session_id
|
@@ -104,6 +119,7 @@ module CS
|
|
104
119
|
end
|
105
120
|
|
106
121
|
def parse_response
|
122
|
+
return unless @response_body
|
107
123
|
@response_code = @response_body.response.code.to_i
|
108
124
|
@response_headers = @response_body.headers
|
109
125
|
if @response_code >= 400
|
data/lib/cs/cli/cli.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module CS
|
4
|
+
module CLI
|
5
|
+
class Config
|
6
|
+
@@config = {}
|
7
|
+
@@loaded = false
|
8
|
+
@@file = ""
|
9
|
+
|
10
|
+
def self.load_config(file="#{ENV['HOME']}/.cs.yml")
|
11
|
+
@@file = file
|
12
|
+
@@config = YAML.load_file(file)
|
13
|
+
@@loaded = true
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.get(key=nil)
|
17
|
+
if !@@loaded
|
18
|
+
STDERR.puts("WARNING could not load '#{@@file}'. Is it exists ?")
|
19
|
+
end
|
20
|
+
|
21
|
+
if key.nil?
|
22
|
+
return @@config
|
23
|
+
else
|
24
|
+
return @@config[key.to_s]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module CS
|
4
|
+
module Collection
|
5
|
+
class SensorDataCollection < SimpleDelegator
|
6
|
+
attr_accessor :session
|
7
|
+
attr_accessor :batch_size
|
8
|
+
|
9
|
+
def initialize(session=nil)
|
10
|
+
self.session = session
|
11
|
+
@batch_size = 1000
|
12
|
+
super([])
|
13
|
+
end
|
14
|
+
|
15
|
+
def save!
|
16
|
+
check_session!
|
17
|
+
|
18
|
+
# group batch
|
19
|
+
self.each_slice(@batch_size) do |batch|
|
20
|
+
body = process_batch(batch)
|
21
|
+
@session.post(get_url, body)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Given array of sensor data it will group the data by sensor_id
|
27
|
+
# and construct payload for multiple sensor upload
|
28
|
+
def process_batch(batch)
|
29
|
+
sensors = {}
|
30
|
+
batch.each do |point|
|
31
|
+
next if point.nil? || point.sensor_id.nil?
|
32
|
+
sensor_id = point.sensor_id
|
33
|
+
|
34
|
+
if !sensors[sensor_id]
|
35
|
+
sensors[sensor_id] = {
|
36
|
+
sensor_id: sensor_id,
|
37
|
+
data: []
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
sensors[sensor_id][:data].push(point.to_cs_value)
|
42
|
+
end
|
43
|
+
|
44
|
+
retval = []
|
45
|
+
sensors.each do |k, v|
|
46
|
+
retval.push(v)
|
47
|
+
end
|
48
|
+
|
49
|
+
{sensors: retval}
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_url
|
53
|
+
"/sensors/data.json"
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def check_session!
|
58
|
+
raise Error::SessionEmptyError unless @session
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/cs/end_point.rb
CHANGED
data/lib/cs/end_point/sensor.rb
CHANGED
@@ -26,8 +26,8 @@ module CS
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
def
|
29
|
+
|
30
|
+
def to_cs_value
|
31
31
|
param = self.to_h(false)
|
32
32
|
if param[:data_type] == "json"
|
33
33
|
if param[:data_structure] && !param[:data_structure].kind_of?(String)
|
@@ -35,12 +35,40 @@ module CS
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
|
38
|
+
param
|
39
|
+
end
|
40
|
+
|
41
|
+
# overide Endpoint#to_parameters
|
42
|
+
def to_parameters
|
43
|
+
{sensor: to_cs_value}
|
39
44
|
end
|
40
45
|
|
41
46
|
def data
|
42
47
|
Relation::SensorDataRelation.new(self.id, self.session)
|
43
48
|
end
|
49
|
+
|
50
|
+
# Copy data from other sensor
|
51
|
+
#
|
52
|
+
# example :
|
53
|
+
#
|
54
|
+
# source = client.sensors.find(1234)
|
55
|
+
# destination = clint.sensors.find(2345)
|
56
|
+
#
|
57
|
+
# destination.copy_data(source, start_date: 12345, end_date: 12350)
|
58
|
+
#
|
59
|
+
def copy_data(sensor, parameters={})
|
60
|
+
source = sensor.data
|
61
|
+
parameters.each do |k,v|
|
62
|
+
source.send(k.to_sym, v)
|
63
|
+
end
|
64
|
+
|
65
|
+
collection = self.data.collection
|
66
|
+
source.each do |point|
|
67
|
+
collection.push self.data.build(date: point.date, value: point.value)
|
68
|
+
end
|
69
|
+
|
70
|
+
collection.save!
|
71
|
+
end
|
44
72
|
end
|
45
73
|
end
|
46
74
|
end
|
@@ -26,7 +26,7 @@ module CS
|
|
26
26
|
resources "data"
|
27
27
|
resource "data"
|
28
28
|
|
29
|
-
def
|
29
|
+
def to_cs_value
|
30
30
|
param = self.to_h(false)
|
31
31
|
param.delete(:sensor_id)
|
32
32
|
value = param[:value]
|
@@ -35,7 +35,12 @@ module CS
|
|
35
35
|
end
|
36
36
|
|
37
37
|
param[:date] = CS::Time.new(date).to_f if param[:date]
|
38
|
-
|
38
|
+
|
39
|
+
param
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_parameters
|
43
|
+
{data: [to_cs_value]}
|
39
44
|
end
|
40
45
|
|
41
46
|
def date_human
|
data/lib/cs/relation.rb
CHANGED
@@ -45,7 +45,7 @@ module CS
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def get_data(params={})
|
48
|
-
get_data!(params)
|
48
|
+
get_data!(params)
|
49
49
|
end
|
50
50
|
|
51
51
|
def all
|
@@ -94,7 +94,6 @@ module CS
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def last
|
97
|
-
total = count
|
98
97
|
resource = get_single_resource(page: count - 1)
|
99
98
|
parse_single_resource(resource)
|
100
99
|
end
|
@@ -146,7 +145,7 @@ module CS
|
|
146
145
|
options[:page] = self.page
|
147
146
|
data = get_data(options)
|
148
147
|
|
149
|
-
data = data[resource_class.resources_name]
|
148
|
+
data = data[resource_class.resources_name] unless data.nil?
|
150
149
|
if !data.nil? && !data.empty?
|
151
150
|
yield data
|
152
151
|
self.page += 1
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CS
|
2
|
+
module Relation
|
3
|
+
class NotificationRelation
|
4
|
+
include Relation
|
5
|
+
|
6
|
+
parameter :page, Integer, default: 0, required: true
|
7
|
+
parameter :per_page, Integer, default: 1000, required: true, maximum: 1000
|
8
|
+
parameter :total, Boolean
|
9
|
+
|
10
|
+
private
|
11
|
+
def resource_class
|
12
|
+
EndPoint::Notification
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_url
|
16
|
+
"/notifications.json"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -50,6 +50,14 @@ module CS
|
|
50
50
|
parse_single_resource(data)
|
51
51
|
end
|
52
52
|
|
53
|
+
def start_date(date)
|
54
|
+
from(date)
|
55
|
+
end
|
56
|
+
|
57
|
+
def end_date(date)
|
58
|
+
to(date)
|
59
|
+
end
|
60
|
+
|
53
61
|
def from(start_date)
|
54
62
|
param_option = self.class.parameters[:start_date]
|
55
63
|
self.start_date = process_param_time(:start_date, start_date, param_option)
|
@@ -62,6 +70,10 @@ module CS
|
|
62
70
|
self
|
63
71
|
end
|
64
72
|
|
73
|
+
def collection
|
74
|
+
Collection::SensorDataCollection.new(session)
|
75
|
+
end
|
76
|
+
|
65
77
|
private
|
66
78
|
def resource_class
|
67
79
|
EndPoint::SensorData
|
@@ -100,6 +100,23 @@ module CS
|
|
100
100
|
self.select { |sensor| sensor.name =~ regex }
|
101
101
|
end
|
102
102
|
|
103
|
+
def triggers()
|
104
|
+
Relation::SensorTriggersRelation.new(@session)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Create new sensor with properties from other sensor
|
108
|
+
#
|
109
|
+
# example :
|
110
|
+
#
|
111
|
+
# client.sensors.clone_from(client.sensors.find(123))
|
112
|
+
def clone_from(other_sensor)
|
113
|
+
sensor = EndPoint::Sensor.new(other_sensor.to_cs_value)
|
114
|
+
sensor.id = nil
|
115
|
+
sensor.session = self.session
|
116
|
+
|
117
|
+
sensor
|
118
|
+
end
|
119
|
+
|
103
120
|
private
|
104
121
|
def resource_class
|
105
122
|
EndPoint::Sensor
|
@@ -109,5 +126,15 @@ module CS
|
|
109
126
|
"/sensors.json"
|
110
127
|
end
|
111
128
|
end
|
129
|
+
|
130
|
+
class SensorTriggersRelation
|
131
|
+
include Relation
|
132
|
+
|
133
|
+
parameter :page, Integer, default: 0, required: true
|
134
|
+
|
135
|
+
def get_url
|
136
|
+
"/sensors/triggers.json"
|
137
|
+
end
|
138
|
+
end
|
112
139
|
end
|
113
140
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CS
|
2
|
+
module Relation
|
3
|
+
class TriggerRelation
|
4
|
+
include Relation
|
5
|
+
|
6
|
+
parameter :page, Integer, default: 0, required: true
|
7
|
+
parameter :per_page, Integer, default: 1000, required: true, maximum: 1000
|
8
|
+
parameter :total, Boolean
|
9
|
+
|
10
|
+
|
11
|
+
private
|
12
|
+
def resource_class
|
13
|
+
EndPoint::Trigger
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_url
|
17
|
+
"/triggers.json"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/cs/session.rb
CHANGED
@@ -13,9 +13,9 @@ module CS
|
|
13
13
|
|
14
14
|
# login to commonsense
|
15
15
|
# @return [String] session_id
|
16
|
-
def login(username, password)
|
16
|
+
def login(username, password, digest=true)
|
17
17
|
@auth_proxy = CS::Auth::HTTP.new(@base_uri)
|
18
|
-
@auth_proxy.login(username, password)
|
18
|
+
@auth_proxy.login(username, password, digest)
|
19
19
|
end
|
20
20
|
|
21
21
|
def oauth(consumer_key, consumer_secret, access_token, access_token_secret)
|
@@ -28,11 +28,20 @@ module CS
|
|
28
28
|
auth_proxy.session_id
|
29
29
|
end
|
30
30
|
|
31
|
+
def api_key
|
32
|
+
auth_proxy.api_key
|
33
|
+
end
|
34
|
+
|
31
35
|
def session_id=(session_id)
|
32
36
|
@auth_proxy = CS::Auth::HTTP.new(@base_uri)
|
33
37
|
@auth_proxy.session_id = session_id
|
34
38
|
end
|
35
39
|
|
40
|
+
def api_key=(api_key)
|
41
|
+
@api_key = api_key
|
42
|
+
@auth_proxy = CS::Auth::HTTP.new(@base_uri, api_key)
|
43
|
+
end
|
44
|
+
|
36
45
|
def auth_proxy
|
37
46
|
raise 'The session is not logged in' unless @auth_proxy
|
38
47
|
@auth_proxy
|
@@ -55,18 +64,25 @@ module CS
|
|
55
64
|
logger.info("")
|
56
65
|
logger.info("#{type} #{path}")
|
57
66
|
logger.debug("headers: #{headers.inspect}")
|
58
|
-
|
67
|
+
if ["POST", "PUT"].include?(type)
|
68
|
+
logger.debug("request: #{body.inspect}")
|
69
|
+
else
|
70
|
+
logger.info("request: #{body.inspect}")
|
71
|
+
end
|
59
72
|
end
|
60
73
|
|
61
|
-
def log_response
|
62
|
-
logger.info("
|
63
|
-
logger.debug("
|
74
|
+
def log_response(elapsed)
|
75
|
+
logger.info("result: #{self.response_code} in #{elapsed}ms")
|
76
|
+
logger.debug("response: #{self.response_body}")
|
64
77
|
end
|
65
78
|
|
66
79
|
def execute(type, path, body, headers, &block)
|
80
|
+
start_time = Time.now
|
67
81
|
log_request(type, path, body, headers) if logger
|
68
82
|
response = retry_on_509 { yield }
|
69
|
-
|
83
|
+
|
84
|
+
elapsed = (Time.now - start_time) * 1000.0
|
85
|
+
log_response(elapsed) if logger
|
70
86
|
|
71
87
|
response
|
72
88
|
end
|
@@ -146,7 +162,12 @@ module CS
|
|
146
162
|
end
|
147
163
|
|
148
164
|
def to_s
|
149
|
-
|
165
|
+
if session_id
|
166
|
+
return "SESSION_ID \"#{session_id}\""
|
167
|
+
elsif api_key
|
168
|
+
return "API_KEY \"#{api_key}\""
|
169
|
+
end
|
170
|
+
return ""
|
150
171
|
end
|
151
172
|
|
152
173
|
def inspect
|