alula-ruby 2.29.0 → 2.30.0
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/VERSION.md +1 -0
- data/lib/alula/client.rb +51 -4
- data/lib/alula/errors.rb +28 -0
- data/lib/alula/m2m_response.rb +22 -0
- data/lib/alula/m2m_rest_resource.rb +17 -0
- data/lib/alula/resources/m2m/m2m_central_station.rb +111 -0
- data/lib/alula/resources/permitted_central_station.rb +55 -0
- data/lib/alula/version.rb +1 -1
- data/lib/alula.rb +6 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e01ef49bc046ae1795d32869b79a7e4b92996c0d35e3cee3cfd2de8df534dcd2
|
|
4
|
+
data.tar.gz: 62d790ddc15244480f6ab1e08d5b77738a92aaeb94a6d286c2a82c9229694267
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 107146e1b827e0f7d8418ca3339d114c27f18750658e73af54e25b6190e65b0857983c93dd8862105b7ffdd2f039a0f1c142db6e2ae948c8b882d5912c561e2c
|
|
7
|
+
data.tar.gz: f095933709d5855fca510bfe3700409e6f1e97e2ab116dc1f9e88f2e845c94ec45ed2f41457536a03b4ab4038f23f5f9ad055b07127d6ebb7e8b49ffa626fb17
|
data/VERSION.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
| Version | Date | Description |
|
|
4
4
|
| ------- | ------------| --------------------------------------------------------------------------- |
|
|
5
|
+
| v2.30.0 | 2025-12-16 | Adds M2MCentralStation and PermittedCentralStation |
|
|
5
6
|
| v2.29.0 | 2025-12-01 | Adds User Impersonation Requests and new Meta |
|
|
6
7
|
| v2.28.0 | 2025-11-19 | Add product_sku Device property |
|
|
7
8
|
| v2.27.1 | 2025-11-14 | Add ONVIF feature support for CONNECT-FLX-DUAL and CONNECT-FLX-DUAL-Z devices |
|
data/lib/alula/client.rb
CHANGED
|
@@ -18,8 +18,37 @@ module Alula
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def request(http_method, resource_path, filters = {}, opts = {})
|
|
21
|
+
if resource_path.match(%r{^/m2m/})
|
|
22
|
+
request_m2m(http_method, resource_path, filters, opts)
|
|
23
|
+
else
|
|
24
|
+
request_alula(http_method, resource_path, filters, opts)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def request_m2m(http_method, resource_path, filters = {}, opts = {})
|
|
31
|
+
validate_request!(http_method, resource_path)
|
|
32
|
+
request_opts = build_options_m2m(http_method, resource_path, filters, opts)
|
|
33
|
+
api_url = config.api_url
|
|
34
|
+
request_resource_path = resource_path
|
|
35
|
+
|
|
36
|
+
# TODO: Handle network failures
|
|
37
|
+
response = make_request(http_method, api_url + request_resource_path, request_opts)
|
|
38
|
+
|
|
39
|
+
begin
|
|
40
|
+
resp = M2MResponse.from_httparty_response(response)
|
|
41
|
+
rescue JSON::ParserError
|
|
42
|
+
# TODO: Should be able to send better info up with this
|
|
43
|
+
raise 'Unable to decode JSON'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
resp
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def request_alula(http_method, resource_path, filters = {}, opts = {})
|
|
21
50
|
validate_request!(http_method, resource_path) unless resource_path.match(%r{^/public/v1})
|
|
22
|
-
request_opts =
|
|
51
|
+
request_opts = build_options_alula(http_method, resource_path, filters, opts)
|
|
23
52
|
api_url = video_request?(resource_path) ? config.video_api_url : config.api_url
|
|
24
53
|
request_resource_path = video_request?(resource_path) ? resource_path.gsub(%r{^/video}, '') : resource_path
|
|
25
54
|
|
|
@@ -36,8 +65,6 @@ module Alula
|
|
|
36
65
|
resp
|
|
37
66
|
end
|
|
38
67
|
|
|
39
|
-
private
|
|
40
|
-
|
|
41
68
|
def validate_request!(http_method, resource_path)
|
|
42
69
|
config.ensure_api_key_set
|
|
43
70
|
config.ensure_api_url_set
|
|
@@ -64,7 +91,27 @@ module Alula
|
|
|
64
91
|
resource_path.match(%r{^/video})
|
|
65
92
|
end
|
|
66
93
|
|
|
67
|
-
def
|
|
94
|
+
def build_options_m2m(http_method, resource_path, filters = {}, opts = {})
|
|
95
|
+
api_key = Alula::Client.config.impersonator_api_key || Alula::Client.config.api_key
|
|
96
|
+
request_opts = {
|
|
97
|
+
headers: {
|
|
98
|
+
'Authorization': "Bearer #{api_key}",
|
|
99
|
+
'User-Agent': "#{Alula::Client.config.user_agent || 'No Agent Set'}/alula-ruby v#{Alula::VERSION}"
|
|
100
|
+
}
|
|
101
|
+
}.merge(opts)
|
|
102
|
+
|
|
103
|
+
request_opts[:headers]['Content-Type'] = 'application/json'
|
|
104
|
+
request_opts[:body] = opts[:multipart] ? filters : JSON.generate(filters)
|
|
105
|
+
|
|
106
|
+
if Alula::Client.config.debug
|
|
107
|
+
request_opts[:debug_output] = Alula.logger
|
|
108
|
+
logger Alula.logger, :info
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
request_opts
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def build_options_alula(http_method, resource_path, filters = {}, opts = {})
|
|
68
115
|
api_key = Alula::Client.config.impersonator_api_key || Alula::Client.config.api_key
|
|
69
116
|
request_opts = {
|
|
70
117
|
headers: {
|
data/lib/alula/errors.rb
CHANGED
|
@@ -231,4 +231,32 @@ module Alula
|
|
|
231
231
|
@errors = errors
|
|
232
232
|
end
|
|
233
233
|
end
|
|
234
|
+
|
|
235
|
+
class M2MError < AlulaError
|
|
236
|
+
attr_reader :error_code
|
|
237
|
+
|
|
238
|
+
def self.for_response(response)
|
|
239
|
+
if response.data['Success'] == false
|
|
240
|
+
self.m2m_error_for_response(response)
|
|
241
|
+
else
|
|
242
|
+
super response
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
private
|
|
247
|
+
|
|
248
|
+
def self.m2m_error_for_response(response)
|
|
249
|
+
error_code = response.data['ErrorCode']
|
|
250
|
+
error = response.data['ErrorString']
|
|
251
|
+
message = self.build_message(error, error_code)
|
|
252
|
+
BadRequestError.new(message)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def self.build_message(error, code)
|
|
256
|
+
return error unless error.to_s.strip.empty?
|
|
257
|
+
return "M2M request failed with code #{code}" if code
|
|
258
|
+
|
|
259
|
+
'M2M request failed'
|
|
260
|
+
end
|
|
261
|
+
end
|
|
234
262
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require_relative 'alula_response'
|
|
2
|
+
|
|
3
|
+
module Alula
|
|
4
|
+
class M2MResponse < AlulaResponse
|
|
5
|
+
attr_accessor :data, :http_body, :http_headers, :http_status, :raw, :rate_limit
|
|
6
|
+
|
|
7
|
+
def ok?
|
|
8
|
+
super && self.data['Success'] == true
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.from_httparty_response(response)
|
|
12
|
+
resp = M2MResponse.new
|
|
13
|
+
resp.data = response.parsed_response
|
|
14
|
+
resp.http_body = response.body
|
|
15
|
+
resp.http_headers = response.headers
|
|
16
|
+
resp.rate_limit = Alula::RateLimit.new(response.headers)
|
|
17
|
+
resp.http_status = response.code
|
|
18
|
+
resp.raw = response
|
|
19
|
+
resp
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Alula
|
|
2
|
+
class M2MRestResource < ApiResource
|
|
3
|
+
def self.resource_url(id = nil)
|
|
4
|
+
if self == M2MRestResource
|
|
5
|
+
raise NotImplementedError, "Cannot call resource_url on a M2MRestResource. Try using M2MCentralStation instead."
|
|
6
|
+
end
|
|
7
|
+
base_path = "/m2m/bll/v3/external"
|
|
8
|
+
return base_path if id.nil?
|
|
9
|
+
|
|
10
|
+
[base_path, id].join('/').gsub(%r{/+}, '/').sub(%r{/$}, '')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def resource_url(id = nil)
|
|
14
|
+
self.class.resource_url(id)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Please forget about abstractions if working with M2M API. Endpoints are
|
|
4
|
+
# inconsistent and do not follow REST principles.
|
|
5
|
+
module Alula
|
|
6
|
+
class M2MCentralStation < Alula::M2MRestResource
|
|
7
|
+
extend Alula::ResourceAttributes
|
|
8
|
+
|
|
9
|
+
DEFAULT_PAGE_NUMBER = 1
|
|
10
|
+
|
|
11
|
+
field :app_name,
|
|
12
|
+
type: :string,
|
|
13
|
+
sortable: false,
|
|
14
|
+
filterable: true,
|
|
15
|
+
creatable_by: [],
|
|
16
|
+
patchable_by: []
|
|
17
|
+
|
|
18
|
+
field :primary_proxy,
|
|
19
|
+
type: :string,
|
|
20
|
+
sortable: false,
|
|
21
|
+
filterable: false,
|
|
22
|
+
creatable_by: [],
|
|
23
|
+
patchable_by: []
|
|
24
|
+
|
|
25
|
+
field :backup_proxy,
|
|
26
|
+
type: :string,
|
|
27
|
+
sortable: false,
|
|
28
|
+
filterable: false,
|
|
29
|
+
creatable_by: [],
|
|
30
|
+
patchable_by: []
|
|
31
|
+
|
|
32
|
+
class << self
|
|
33
|
+
def list(filters = {}, opts = {})
|
|
34
|
+
built_filters = {}
|
|
35
|
+
pagination = filters.delete(:page)
|
|
36
|
+
if pagination
|
|
37
|
+
built_filters['Page'] = pagination[:number]
|
|
38
|
+
built_filters['PageSize'] = pagination[:size]
|
|
39
|
+
end
|
|
40
|
+
response = Alula::Client.request(:post, resource_url('GetAvailableCentralStations'), built_filters, opts)
|
|
41
|
+
if response.ok?
|
|
42
|
+
list = construct_list_from_response(self, response.data.fetch('ResponseBody', {}), pagination)
|
|
43
|
+
list.rate_limit = response.rate_limit
|
|
44
|
+
list
|
|
45
|
+
else
|
|
46
|
+
error_class = M2MError.for_response(response)
|
|
47
|
+
raise error_class
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def retrieve(id)
|
|
52
|
+
built_filters = {}
|
|
53
|
+
built_filters['AppName'] = id
|
|
54
|
+
response = Alula::Client.request(:post, self.resource_url('GetCentralStationProxies'), built_filters, {})
|
|
55
|
+
if response.ok?
|
|
56
|
+
item = build_model(self, response.data.fetch('ResponseBody', {}))
|
|
57
|
+
item.rate_limit = response.rate_limit
|
|
58
|
+
item
|
|
59
|
+
else
|
|
60
|
+
error_class = M2MError.for_response(response)
|
|
61
|
+
raise error_class
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def method_missing(method, *args, &block)
|
|
66
|
+
query = QueryInterface.new(self)
|
|
67
|
+
return query.public_send(method, *args, &block) if query.respond_to?(method)
|
|
68
|
+
|
|
69
|
+
super
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def respond_to_missing?(method, include_private = false)
|
|
73
|
+
QueryInterface.new(self).respond_to?(method, include_private) || super
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def construct_list_from_response(klass, response_body, pagination)
|
|
79
|
+
list = ListObject.new(klass)
|
|
80
|
+
Array(response_body.fetch('AvailableCentralStations', [])).each do |item|
|
|
81
|
+
next unless item.is_a?(Hash)
|
|
82
|
+
|
|
83
|
+
list << build_model(klass, item)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
list.set_meta Meta.new(
|
|
87
|
+
'page' => {
|
|
88
|
+
'total' => response_body['TotalCount'] || list.length,
|
|
89
|
+
'number' => pagination[:number],
|
|
90
|
+
'size' => pagination[:size]
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
list
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def build_model(klass, attributes)
|
|
97
|
+
sanitized_attributes = attributes.each_with_object({}) do |(key, value), memo|
|
|
98
|
+
memo[Util.camelize(Util.underscore(key.to_s))] = value
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
klass.new(sanitized_attributes['appName'], sanitized_attributes)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def extract_page_value(pagination, key)
|
|
105
|
+
return nil unless pagination.is_a?(Hash)
|
|
106
|
+
|
|
107
|
+
pagination[key] || pagination[key.to_s]
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Alula
|
|
2
|
+
class PermittedCentralStation < Alula::RestResource
|
|
3
|
+
extend Alula::ResourceAttributes
|
|
4
|
+
extend Alula::RelationshipAttributes
|
|
5
|
+
extend Alula::ApiOperations::Request
|
|
6
|
+
extend Alula::ApiOperations::List
|
|
7
|
+
extend Alula::ApiOperations::Save
|
|
8
|
+
extend Alula::ApiOperations::Delete
|
|
9
|
+
|
|
10
|
+
resource_path 'dealers/permittedCentralStations'
|
|
11
|
+
type 'dealers-permittedCentralStations'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
relationship :dealer, type: 'dealers', cardinality: 'To-one'
|
|
15
|
+
|
|
16
|
+
# Resource Fields
|
|
17
|
+
# Not all params are used at the moment. See Alula::ResourceAttributes for details
|
|
18
|
+
# on how params are parsed,
|
|
19
|
+
field :id,
|
|
20
|
+
type: :string,
|
|
21
|
+
sortable: false,
|
|
22
|
+
filterable: false,
|
|
23
|
+
creatable_by: [:system],
|
|
24
|
+
patchable_by: []
|
|
25
|
+
|
|
26
|
+
field :dealer_id,
|
|
27
|
+
type: :string,
|
|
28
|
+
sortable: false,
|
|
29
|
+
filterable: false,
|
|
30
|
+
creatable_by: [:system],
|
|
31
|
+
patchable_by: []
|
|
32
|
+
|
|
33
|
+
field :remote_central_station_id,
|
|
34
|
+
type: :string,
|
|
35
|
+
sortable: false,
|
|
36
|
+
filterable: true,
|
|
37
|
+
creatable_by: [:system],
|
|
38
|
+
patchable_by: []
|
|
39
|
+
|
|
40
|
+
field :created_by,
|
|
41
|
+
type: :string,
|
|
42
|
+
sortable: false,
|
|
43
|
+
filterable: false,
|
|
44
|
+
creatable_by: [],
|
|
45
|
+
patchable_by: []
|
|
46
|
+
|
|
47
|
+
field :created_at,
|
|
48
|
+
type: :date,
|
|
49
|
+
sortable: false,
|
|
50
|
+
filterable: false,
|
|
51
|
+
creatable_by: [],
|
|
52
|
+
patchable_by: []
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/alula/version.rb
CHANGED
data/lib/alula.rb
CHANGED
|
@@ -11,6 +11,8 @@ require_relative 'alula/api_operations/request'
|
|
|
11
11
|
require_relative 'alula/api_operations/save'
|
|
12
12
|
require_relative 'alula/api_operations/delete'
|
|
13
13
|
require_relative 'alula/api_resource'
|
|
14
|
+
require_relative 'alula/m2m_rest_resource'
|
|
15
|
+
require_relative 'alula/m2m_response'
|
|
14
16
|
|
|
15
17
|
require_relative 'alula/dcp/error_handler'
|
|
16
18
|
require_relative 'alula/dcp/list_object'
|
|
@@ -147,9 +149,11 @@ require_relative 'alula/resources/feature_price'
|
|
|
147
149
|
require_relative 'alula/resources/feature_bysubject'
|
|
148
150
|
require_relative 'alula/resources/nfc_tag'
|
|
149
151
|
require_relative 'alula/resources/sim_card'
|
|
152
|
+
require_relative 'alula/resources/permitted_central_station'
|
|
150
153
|
require_relative 'alula/resources/dcp/config/synchronize'
|
|
151
154
|
require_relative 'alula/resources/video/base_resource'
|
|
152
155
|
require_relative 'alula/resources/video/device'
|
|
156
|
+
require_relative 'alula/resources/m2m/m2m_central_station'
|
|
153
157
|
|
|
154
158
|
require_relative 'alula/procedures/device_cellular_history_proc'
|
|
155
159
|
require_relative 'alula/procedures/device_rateplan_get_proc'
|
|
@@ -237,6 +241,8 @@ module Alula
|
|
|
237
241
|
Alula::ReceiverBind,
|
|
238
242
|
Alula::Revision,
|
|
239
243
|
Alula::Self,
|
|
244
|
+
Alula::M2MCentralStation,
|
|
245
|
+
Alula::PermittedCentralStation,
|
|
240
246
|
Alula::Station,
|
|
241
247
|
Alula::User,
|
|
242
248
|
Alula::UserAddress,
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: alula-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.30.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Titus Johnson
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-12-
|
|
11
|
+
date: 2025-12-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: httparty
|
|
@@ -225,6 +225,8 @@ files:
|
|
|
225
225
|
- lib/alula/helpers/device_helpers/program_id_helper.rb
|
|
226
226
|
- lib/alula/helpers/jwt_helper.rb
|
|
227
227
|
- lib/alula/list_object.rb
|
|
228
|
+
- lib/alula/m2m_response.rb
|
|
229
|
+
- lib/alula/m2m_rest_resource.rb
|
|
228
230
|
- lib/alula/meta.rb
|
|
229
231
|
- lib/alula/monkey_patches.rb
|
|
230
232
|
- lib/alula/oauth.rb
|
|
@@ -341,8 +343,10 @@ files:
|
|
|
341
343
|
- lib/alula/resources/feature_planvideo.rb
|
|
342
344
|
- lib/alula/resources/feature_price.rb
|
|
343
345
|
- lib/alula/resources/helix_user.rb
|
|
346
|
+
- lib/alula/resources/m2m/m2m_central_station.rb
|
|
344
347
|
- lib/alula/resources/nfc_tag.rb
|
|
345
348
|
- lib/alula/resources/oauth_client.rb
|
|
349
|
+
- lib/alula/resources/permitted_central_station.rb
|
|
346
350
|
- lib/alula/resources/receiver.rb
|
|
347
351
|
- lib/alula/resources/receiver_bind.rb
|
|
348
352
|
- lib/alula/resources/receiver_connection.rb
|