oklog-api 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2ade0502599e017e35719e5ab72d43a7d496c1cbe831f4de48dba5096d103ea7
4
+ data.tar.gz: d2c926c063c82f889ecaaebe78cbd1e165d77d655d048e0e4362402a2f98d0ef
5
+ SHA512:
6
+ metadata.gz: 01535c9bc906254cbea3ad0664bdaeb306ca6db8c999dc0f275b9b12cd6539e9552519206d411000db5f6188fd20340a8990666f984f76a80f1e95283fce3b2f
7
+ data.tar.gz: 4832f39fb0f6e4bae1141ff181b3e15df4d0657f5e17b03e95e3c885ba1169acdb429280c15c56a12f92e2623c70737cfbc478a2e64a39067e7813e8baba8101
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ MIT License
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.markdown ADDED
File without changes
@@ -0,0 +1,2 @@
1
+ Description:
2
+ oklog_api:install
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OklogApi
4
+ class InstallGenerator < Rails::Generators::Base
5
+ source_root File.expand_path('templates', __dir__)
6
+
7
+ def generate_install
8
+ copy_file 'oklog_api.yml', 'config/oklog_api.yml'
9
+ copy_file 'oklog_api.rb', 'config/initializers/oklog_api.rb'
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,24 @@
1
+ require 'oklog-api'
2
+
3
+ OklogApi.setup do |config|
4
+ if File.exist?('config/oklog_api.yml')
5
+ processed = YAML.load('config/oklog_api.yml', aliases: true)[Rails.env]
6
+
7
+ processed.each do |k, v|
8
+ config::register k.underscore.to_sym, v
9
+ end
10
+
11
+ #config::Request.api_key ||= ENV['API_KEY']
12
+
13
+ config::Request.api_user_email ||= ENV['API_USER_EMAIL']
14
+ config::Request.api_user_password ||= ENV['API_USER_PASSWORD']
15
+
16
+ config::Request.timeout = 60
17
+ config::Request.open_timeout = 60
18
+ config::Request.symbolize_keys = true
19
+ config::Request.debug = false
20
+ config::Request.debug_options = { headers: true, bodies: false, errors: false, log_level: :info } # https://lostisland.github.io/faraday/middleware/logger
21
+
22
+ config::Request.language = defined?(I18n) ? I18n.locale : :ru
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ defaults: &defaults
2
+ API_ENDPOINT: "https://rail-scan.com"
3
+ UNION_ENDPOINT: "http://192.168.88.38:8000"
4
+ NOTIFY_ENDPOINT: "http://192.168.1.153:3003"
5
+
6
+ API_AUTH_METHOD: "api_key"
7
+ API_KEY: "***"
8
+
9
+ API_USER_EMAIL: ""
10
+ API_USER_PASSWORD: ""
11
+
12
+ KEYCLOAK_TOKEN_URL: "https://iam.ctm.ru/auth/realms/ctm/protocol/openid-connect/token"
13
+ KEYCLOAK_GRANT_TYPE: "password"
14
+ KEYCLOAK_CLIENT_ID: "client_id"
15
+ KEYCLOAK_CLIENT_SECRET: "client_secret"
16
+ KEYCLOAK_REDIRECT_URI: "http://yousite.ru/callback"
17
+ production:
18
+ <<: *defaults
19
+ UNION_ENDPOINT: "http://192.168.1.88:3500"
20
+ NOTIFY_ENDPOINT: "http://192.168.1.153:3003"
21
+ development:
22
+ <<: *defaults
23
+ test:
24
+ <<: *defaults
@@ -0,0 +1,427 @@
1
+ module OklogApi
2
+ class APIRequest
3
+
4
+ def initialize(builder: nil)
5
+ @request_builder = builder
6
+ end
7
+
8
+ def post(params: nil, headers: nil, format: nil, body: {})
9
+ validate_api_key
10
+ begin
11
+ headers ||= {}
12
+ if is_multipart?(body)
13
+ if self.api_auth_method == :base64
14
+ headers['Authorization'] = "Basic " + Base64::encode64("#{self.api_user_email}:#{self.api_user_password}")
15
+ end
16
+ if [:keycloak].include?(self.api_auth_method)
17
+ unless OklogApi::Request.token_alive?(OklogApi::Request.access_token)
18
+ if OklogApi::Request.token_alive?(OklogApi::Request.refresh_token)
19
+ response = OklogApi.refresh_access_token
20
+ OklogApi::Request.access_token = response.try(:dig, "access_token")
21
+ OklogApi::Request.refresh_token = response.try(:dig, "refresh_token")
22
+ else
23
+ error_params = { title: "UNAUTHORIZED", status_code: 401 }
24
+ error = OklogApiError.new("Token is unavailable", error_params)
25
+ raise error
26
+ end
27
+ end
28
+ headers['Authorization'] = "Bearer #{OklogApi::Request.access_token}"
29
+ end
30
+ if [:api_key].include?(self.api_auth_method)
31
+ request.headers['X-Api-Key'] = "#{OklogApi::Request.api_key}"
32
+ if self.api_user_id.present?
33
+ request.headers['X-User-Id'] = self.api_user_id.to_s
34
+ end
35
+ end
36
+ headers['User-Agent'] = "OklogApi/#{OklogApi::VERSION} Ruby gem"
37
+ headers['Accept-Language'] = OklogApi::Request.language.to_s
38
+ if @request_builder.without_ratelimit
39
+ headers['X-Is-Request-Without-RateLimit'] = "true"
40
+ end
41
+ if @request_builder.is_allow_access_to_coordinates
42
+ headers['X-Is-Allow-Access-To-Coordinates'] = "true"
43
+ end
44
+ url = URI("#{self.api_url}#{format.present? ? ".#{format}": ""}")
45
+ http = Net::HTTP.new(url.host, url.port);
46
+ request = Net::HTTP::Post.new(url, headers)
47
+ request.set_form body.to_params, 'multipart/form-data'
48
+ if @request_builder.debug
49
+ p request
50
+ end
51
+ http.request(request)
52
+ else
53
+ response = self.rest_client(format).post do |request|
54
+ configure_request(request: request, params: params, headers: headers, body: body)
55
+ end
56
+ if [nil, 'json'].include?(format)
57
+ parse_response(response)
58
+ else
59
+ response
60
+ end
61
+ end
62
+ rescue => e
63
+ handle_error(e)
64
+ end
65
+ end
66
+
67
+ def get(params: nil, headers: nil, format: nil, body: {})
68
+ validate_api_key
69
+
70
+ begin
71
+ response = self.rest_client(format).get do |request|
72
+ configure_request(request: request, params: params, headers: headers, body: body)
73
+ end
74
+ if [nil, 'json'].include?(format)
75
+ parse_response(response)
76
+ else
77
+ response
78
+ end
79
+ rescue => e
80
+ handle_error(e)
81
+ end
82
+ end
83
+
84
+ def delete(params: nil, headers: nil, format: nil, body: {})
85
+ validate_api_key
86
+ begin
87
+ response = self.rest_client(format).delete do |request|
88
+ configure_request(request: request, params: params, headers: headers, body: body)
89
+ end
90
+ if [nil, 'json'].include?(format)
91
+ parse_response(response)
92
+ else
93
+ response
94
+ end
95
+ rescue => e
96
+ handle_error(e)
97
+ end
98
+ end
99
+
100
+ def patch(params: nil, headers: nil, format: nil, body: {})
101
+ validate_api_key
102
+ begin
103
+ response = self.rest_client(format).patch do |request|
104
+ configure_request(request: request, params: params, headers: headers, body: body)
105
+ end
106
+ if [nil, 'json'].include?(format)
107
+ parse_response(response)
108
+ else
109
+ response
110
+ end
111
+ rescue => e
112
+ handle_error(e)
113
+ end
114
+ end
115
+
116
+ def put(params: nil, headers: nil, format: nil, body: {})
117
+ validate_api_key
118
+ begin
119
+ response = self.rest_client(format).put do |request|
120
+ configure_request(request: request, params: params, headers: headers, body: body)
121
+ end
122
+ if [nil, 'json'].include?(format)
123
+ parse_response(response)
124
+ else
125
+ response
126
+ end
127
+ rescue => e
128
+ handle_error(e)
129
+ end
130
+ end
131
+
132
+ protected
133
+
134
+ # Convenience accessors
135
+
136
+ def access_token
137
+ @request_builder.access_token
138
+ end
139
+
140
+ def refresh_token
141
+ @request_builder.refresh_token
142
+ end
143
+
144
+ def api_user_id
145
+ @request_builder.api_user_id
146
+ end
147
+
148
+ def api_key
149
+ @request_builder.api_key
150
+ end
151
+
152
+ def api_user_email
153
+ @request_builder.api_user_email
154
+ end
155
+
156
+ def api_user_password
157
+ @request_builder.api_user_password
158
+ end
159
+
160
+ def api_auth_method
161
+ @request_builder.api_auth_method
162
+ end
163
+
164
+ def api_endpoint
165
+ @request_builder.api_endpoint
166
+ end
167
+
168
+ def union_endpoint
169
+ @request_builder.union_endpoint
170
+ end
171
+
172
+ def notify_endpoint
173
+ @request_builder.notify_endpoint
174
+ end
175
+
176
+ def timeout
177
+ @request_builder.timeout
178
+ end
179
+
180
+ def open_timeout
181
+ @request_builder.open_timeout
182
+ end
183
+
184
+ def proxy
185
+ @request_builder.proxy
186
+ end
187
+
188
+ def ssl_options
189
+ @request_builder.ssl_options
190
+ end
191
+
192
+ def adapter
193
+ @request_builder.faraday_adapter
194
+ end
195
+
196
+ def symbolize_keys
197
+ @request_builder.symbolize_keys
198
+ end
199
+
200
+ # Helpers
201
+
202
+ def handle_error(error)
203
+ error_params = {}
204
+
205
+ begin
206
+ if error.is_a?(Faraday::ClientError) && error.response
207
+ error_params[:status_code] = error.response[:status]
208
+ error_params[:raw_body] = error.response[:body]
209
+
210
+ parsed_response = MultiJson.load(error.response[:body], symbolize_keys: symbolize_keys)
211
+
212
+ if parsed_response
213
+ error_params[:body] = parsed_response
214
+
215
+ title_key = symbolize_keys ? :title : "title"
216
+ detail_key = symbolize_keys ? :detail : "detail"
217
+
218
+ error_params[:title] = parsed_response[title_key] if parsed_response[title_key]
219
+ error_params[:detail] = parsed_response[detail_key] if parsed_response[detail_key]
220
+ end
221
+
222
+ end
223
+ rescue MultiJson::ParseError
224
+ end
225
+
226
+ error_to_raise = OklogApiError.new(error.message, error_params)
227
+
228
+ raise error_to_raise
229
+ end
230
+
231
+ def configure_request(request: nil, params: nil, headers: nil, body: nil)
232
+ if request
233
+ request.params.merge!(params) if params
234
+ request.headers ||= {}
235
+ request.headers['Content-Type'] = 'application/json'
236
+ if self.api_auth_method == :base64
237
+ request.headers['Authorization'] = "Basic " + Base64::encode64("#{self.api_user_email}:#{self.api_user_password}")
238
+ end
239
+ if [:keycloak].include?(self.api_auth_method)
240
+ unless OklogApi::Request.token_alive?(OklogApi::Request.access_token)
241
+ if OklogApi::Request.token_alive?(OklogApi::Request.refresh_token)
242
+ response = OklogApi.refresh_access_token
243
+ OklogApi::Request.access_token = response.try(:dig, "access_token")
244
+ OklogApi::Request.refresh_token = response.try(:dig, "refresh_token")
245
+ else
246
+ error_params = { title: "UNAUTHORIZED", status_code: 401 }
247
+ error = OklogApiError.new("Token is unavailable", error_params)
248
+ raise error
249
+ end
250
+ end
251
+ request.headers['Authorization'] = "Bearer #{OklogApi::Request.access_token}"
252
+ end
253
+ if [:api_key].include?(self.api_auth_method)
254
+ request.headers['X-Api-Key'] = "#{OklogApi::Request.api_key}"
255
+ if self.api_user_id.present?
256
+ request.headers['X-User-Id'] = self.api_user_id.to_s
257
+ end
258
+ end
259
+ request.headers['User-Agent'] = "OklogApi/#{OklogApi::VERSION} Ruby gem"
260
+ request.headers['Accept-Language'] = OklogApi::Request.language.to_s
261
+ if @request_builder.without_ratelimit
262
+ request.headers['X-Is-Request-Without-RateLimit'] = "true"
263
+ end
264
+ if @request_builder.is_allow_access_to_coordinates
265
+ request.headers['X-Is-Allow-Access-To-Coordinates'] = "true"
266
+ end
267
+ request.headers.merge!(headers) if headers
268
+
269
+ request.body = MultiJson.dump(body) if body && request.headers['Content-Type'] == 'application/json'
270
+
271
+ request.options.timeout = self.timeout
272
+ request.options.open_timeout = self.open_timeout
273
+ end
274
+ end
275
+
276
+ def is_multipart?(body, result=false)
277
+ return false if body == {}
278
+ if body.is_a?(Hash)
279
+ body.inject({}) do |acc, kv|
280
+ result = is_multipart?(kv.last, result)
281
+ end
282
+ elsif body.is_a?(Array)
283
+ body.map do |item|
284
+ result = is_multipart?(item, result)
285
+ end
286
+ result
287
+ elsif [ActionDispatch::Http::UploadedFile, StringIO, Tempfile, File].include?(body.class)
288
+ return true
289
+ else
290
+ result || false
291
+ end
292
+ end
293
+
294
+ def rest_client(format=nil)
295
+ client = Faraday.new("#{self.api_url}#{format.present? ? ".#{format}": ""}", proxy: self.proxy,
296
+ ssl: self.ssl_options) do |faraday|
297
+ faraday.request :gzip
298
+ faraday.response :raise_error
299
+ faraday.adapter adapter
300
+ if @request_builder.debug
301
+ faraday.response :logger, @request_builder.logger, @request_builder.debug_options
302
+ end
303
+ end
304
+ client
305
+ end
306
+
307
+ def parse_response(response)
308
+ parsed_response = nil
309
+
310
+ if response.body && !response.body.empty?
311
+ begin
312
+ headers = response.headers
313
+ body = MultiJson.load(response.body, symbolize_keys: symbolize_keys)
314
+ parsed_response = Response.new(headers: headers, body: body, status_code: response.env.status)
315
+ rescue MultiJson::ParseError
316
+ error_params = { title: "UNPARSEABLE_RESPONSE", status_code: 500 }
317
+ error = OklogApiError.new("Unparseable response: #{response.body}", error_params)
318
+ raise error
319
+ end
320
+ end
321
+
322
+ parsed_response
323
+ end
324
+
325
+ def validate_api_key
326
+ case self.api_auth_method
327
+ when :api_key
328
+ unless self.api_key# && self.api_endpoint
329
+ raise OklogApi::OklogApiError, "You must set an api_key prior to making a call #{self.api_key} #{self.api_endpoint}"
330
+ end
331
+ when :base64
332
+ unless self.api_user_email && self.api_user_password
333
+ raise OklogApi::OklogApiError, "You must set an api_user_email and an api_user_password prior to making a call #{self.api_user_email} #{self.api_user_password} #{self.api_endpoint}"
334
+ end
335
+ when :keycloak
336
+ unless self.access_token || self.refresh_token
337
+ raise OklogApi::OklogApiError, "You must set an access_token or a refresh_token prior to making a call #{self.access_token} #{self.refresh_token} #{self.api_endpoint}"
338
+ end
339
+ else
340
+ raise OklogApi::OklogApiError, "You must set an api_auth_method prior to making a call #{self.api_auth_method} #{self.api_endpoint}"
341
+ end
342
+ end
343
+
344
+ def api_url
345
+ first_path = @request_builder.path_parts.first
346
+ url = case @request_builder.path_parts.first
347
+ when "lk"
348
+ lk_api_url
349
+ when "notify"
350
+ notify_api_url
351
+ when "app"
352
+ app_api_url
353
+ when "union"
354
+ union_api_url
355
+ else
356
+ base_api_url
357
+ end
358
+ @request_builder.path_parts.shift if %w[union notify].include?(first_path)
359
+ url + @request_builder.path
360
+ end
361
+
362
+ def base_api_url
363
+ "#{OklogApi.api_endpoint}/api/v2.0/"
364
+ end
365
+
366
+ def lk_api_url
367
+ "https://rail-scan.com/"
368
+ end
369
+
370
+ def app_api_url
371
+ "https://rail-scan.com/"
372
+ end
373
+
374
+ def union_api_url
375
+ "#{OklogApi.union_endpoint}/api/v1.0/"
376
+ end
377
+
378
+ def notify_api_url
379
+ "#{OklogApi.notify_endpoint}/"
380
+ end
381
+ end
382
+ end
383
+
384
+ class Hash
385
+ def to_params(namespace = nil)
386
+ query = []
387
+ each do |key, value|
388
+ if value.present?
389
+ if value.is_a?(Hash) || value.is_a?(Array)
390
+ query += value.to_params(namespace ? "#{namespace}[#{key}]" : key)
391
+ else
392
+ query << value.to_params(namespace ? "#{namespace}[#{key}]" : key)
393
+ end
394
+ end
395
+ end
396
+ query
397
+ end
398
+ end
399
+
400
+ class Object
401
+ def to_params(key)
402
+ if self.is_a? ActionDispatch::Http::UploadedFile
403
+ [key.to_param, File.open(self.path),
404
+ {
405
+ :filename => self.original_filename,
406
+ :content_type => self.content_type
407
+ }
408
+ ]
409
+ elsif %w[File Tempfile StringIO].include?(self.class.name)
410
+ self
411
+ else
412
+ [key.to_param, to_param.to_s]
413
+ end
414
+ end
415
+ end
416
+
417
+ class Array
418
+ def to_params(key)
419
+ prefix = "#{key}[]"
420
+
421
+ if empty?
422
+ nil.to_params(prefix)
423
+ else
424
+ collect { |value| value.to_params(prefix) }
425
+ end
426
+ end
427
+ end
@@ -0,0 +1,29 @@
1
+ module OklogApi
2
+ class OklogApiError < StandardError
3
+ attr_reader :title, :detail, :body, :raw_body, :status_code
4
+
5
+ def initialize(message = "", params = {})
6
+ @title = params[:title]
7
+ @detail = params[:detail]
8
+ @body = params[:body]
9
+ @raw_body = params[:raw_body]
10
+ @status_code = params[:status_code]
11
+
12
+ super(message)
13
+ end
14
+
15
+ def to_s
16
+ super + " " + instance_variables_to_s
17
+ end
18
+
19
+ private
20
+
21
+ def instance_variables_to_s
22
+ [:title, :detail, :body, :raw_body, :status_code].map do |attr|
23
+ attr_value = send(attr)
24
+
25
+ "@#{attr}=#{attr_value.inspect}"
26
+ end.join(", ")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,161 @@
1
+ module OklogApi
2
+ class Request
3
+ attr_accessor :access_token, :refresh_token, :api_user_id, :api_key, :api_user_email, :api_user_password,
4
+ :api_auth_method, :api_endpoint, :union_endpoint, :notify_endpoint,
5
+ :timeout, :open_timeout, :proxy, :ssl_options, :faraday_adapter, :symbolize_keys, :debug, :debug_options,
6
+ :without_ratelimit, :is_allow_access_to_coordinates, :logger, :test, :language
7
+
8
+ AUTH_METHODS = [:keycloak, :api_key, :base64]
9
+ DEFAULT_AUTH_METHOD = :api_key
10
+ DEFAULT_TIMEOUT = 60
11
+ DEFAULT_OPEN_TIMEOUT = 60
12
+ DEFAULT_LANGUAGE = :ru
13
+
14
+ def initialize(access_token: nil, refresh_token: nil, api_user_id: nil, api_key: nil, api_user_email: nil, api_user_password: nil,
15
+ api_endpoint: nil, union_endpoint: nil, api_auth_method: nil, timeout: nil, open_timeout: nil, proxy: nil, ssl_options: nil,
16
+ faraday_adapter: nil, symbolize_keys: false, debug: false,
17
+ debug_options: { headers: true, bodies: false, errors: false, log_level: :info },
18
+ without_ratelimit: false, is_allow_access_to_coordinates: false,
19
+ logger: nil, test: false, language: DEFAULT_LANGUAGE)
20
+
21
+ @path_parts = []
22
+ @api_key = api_key || self.class.api_key || ENV['RAIL_LOCATOR_API_KEY']
23
+ @api_key = @api_key.strip if @api_key
24
+
25
+ @api_user_id = api_user_id
26
+
27
+ if @api_key == :keycloak
28
+ @access_token = access_token || self.class.access_token || OklogApi.generate_access_token.try(:dig, "access_token")
29
+ @access_token = @access_token.strip if @access_token
30
+ @refresh_token = refresh_token || self.class.refresh_token
31
+ @refresh_token = @refresh_token.strip if @refresh_token
32
+ else
33
+ @access_token = ""
34
+ @refresh_token = ""
35
+ end
36
+
37
+ @api_user_email = api_user_email || ENV['API_USER_EMAIL'] || ""
38
+ @api_user_password = api_user_password || ENV['API_USER_PASSWORD'] || ""
39
+
40
+ @api_endpoint = api_endpoint || self.class.api_endpoint
41
+ @api_endpoint = OklogApi::api_endpoint if @api_endpoint.nil?
42
+ @union_endpoint = union_endpoint || self.class.union_endpoint
43
+ @union_endpoint = OklogApi::union_endpoint if @union_endpoint.nil?
44
+
45
+ @api_auth_method = api_auth_method || OklogApi::api_auth_method || DEFAULT_AUTH_METHOD
46
+ @timeout = timeout || self.class.timeout || DEFAULT_TIMEOUT
47
+ @open_timeout = open_timeout || self.class.open_timeout || DEFAULT_OPEN_TIMEOUT
48
+ @proxy = proxy || self.class.proxy || ENV['RAIL_LOCATOR_API_PROXY']
49
+ @ssl_options = ssl_options || self.class.ssl_options || { version: "TLSv1_2" }
50
+ @faraday_adapter = faraday_adapter || self.class.faraday_adapter || Faraday.default_adapter
51
+ @symbolize_keys = symbolize_keys || self.class.symbolize_keys || false
52
+ @debug = debug || self.class.debug || false
53
+ @debug_options = debug_options || self.class.debug_options || { headers: true, bodies: false, errors: false, log_level: :info }
54
+ @without_ratelimit = without_ratelimit || self.class.without_ratelimit
55
+ @is_allow_access_to_coordinates = is_allow_access_to_coordinates || self.class.is_allow_access_to_coordinates
56
+ @test = test || self.class.test || false
57
+ @language = language || DEFAULT_LANGUAGE
58
+ @logger = logger || self.class.logger || ::Logger.new(STDOUT)
59
+ end
60
+
61
+ def method_missing(method, *args)
62
+ @path_parts << method.to_s.downcase
63
+ @path_parts << args if args.length > 0
64
+ @path_parts.flatten!
65
+ self
66
+ end
67
+
68
+ def respond_to_missing?(method_name, include_private = false)
69
+ true
70
+ end
71
+
72
+ def send(*args)
73
+ if args.length == 0
74
+ method_missing(:send, args)
75
+ else
76
+ __send__(*args)
77
+ end
78
+ end
79
+
80
+ def path_parts
81
+ @path_parts
82
+ end
83
+
84
+ def path
85
+ @path_parts.join('/')
86
+ end
87
+
88
+ def create(params: nil, headers: nil, body: {}, format: nil)
89
+ APIRequest.new(builder: self).post(params: params, headers: headers, body: body, format: format)
90
+ ensure
91
+ reset
92
+ end
93
+
94
+ def update(params: nil, headers: nil, body: {}, format: nil)
95
+ APIRequest.new(builder: self).patch(params: params, headers: headers, body: body, format: format)
96
+ ensure
97
+ reset
98
+ end
99
+
100
+ def insert(params: nil, headers: nil, body: {}, format: nil)
101
+ APIRequest.new(builder: self).put(params: params, headers: headers, body: body, format: format)
102
+ ensure
103
+ reset
104
+ end
105
+
106
+ def retrieve(params: nil, headers: nil, body: {}, format: nil)
107
+ APIRequest.new(builder: self).get(params: params, headers: headers, body: body, format: format)
108
+ ensure
109
+ reset
110
+ end
111
+
112
+ def delete(params: nil, headers: nil, body: {})
113
+ APIRequest.new(builder: self).delete(params: params, headers: headers, body: body)
114
+ ensure
115
+ reset
116
+ end
117
+
118
+ def token_alive?(token, jwt_secret_code=OklogApi.keycloak_client_secret)
119
+ begin
120
+ return false if token.nil?
121
+ exp = JWT.decode(token, jwt_secret_code, false).try(:first).try(:dig, "exp")
122
+ return false if exp.nil?
123
+ Time.at(exp) > Time.now + 30.second
124
+ rescue => e
125
+ #Sentry.capture_exception(e)
126
+ false
127
+ end
128
+ end
129
+
130
+ protected
131
+
132
+ def reset
133
+ @path_parts = []
134
+ end
135
+
136
+ class << self
137
+ attr_accessor :access_token, :refresh_token, :api_user_id, :api_key, :api_user_email, :api_user_password, :api_auth_method,
138
+ :timeout, :open_timeout, :api_endpoint, :union_endpoint, :notify_endpoint,
139
+ :proxy, :ssl_options, :faraday_adapter, :symbolize_keys,
140
+ :debug, :debug_options, :without_ratelimit, :is_allow_access_to_coordinates, :logger, :test, :language
141
+
142
+ def method_missing(sym, *args, &block)
143
+ new(access_token: self.access_token, refresh_token: self.refresh_token,
144
+ api_user_id: self.api_user_id,
145
+ api_key: self.api_key,
146
+ api_user_email: self.api_user_email, api_user_password: self.api_user_password,
147
+ api_auth_method: self.api_auth_method, api_endpoint: self.api_endpoint, union_endpoint: self.union_endpoint,
148
+ timeout: self.timeout, open_timeout: self.open_timeout, faraday_adapter: self.faraday_adapter,
149
+ symbolize_keys: self.symbolize_keys, debug: self.debug, debug_options: self.debug_options,
150
+ without_ratelimit: self.without_ratelimit,
151
+ is_allow_access_to_coordinates: self.is_allow_access_to_coordinates,
152
+ proxy: self.proxy, ssl_options: self.ssl_options, logger: self.logger,
153
+ test: self.test, language: self.language).send(sym, *args, &block)
154
+ end
155
+
156
+ def respond_to_missing?(method_name, include_private = false)
157
+ true
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,11 @@
1
+ module OklogApi
2
+ class Response
3
+ attr_accessor :body, :headers, :status_code
4
+
5
+ def initialize(body: {}, headers: {}, status_code: nil)
6
+ @body = body
7
+ @headers = headers
8
+ @status_code = status_code
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module OklogApi
2
+ VERSION = "1.0.0"
3
+ end
data/lib/oklog-api.rb ADDED
@@ -0,0 +1,91 @@
1
+ require 'faraday'
2
+ require 'faraday/gzip'
3
+ require 'net/http/post/multipart'
4
+ require 'multi_json'
5
+ require 'oklog-api/version'
6
+ require 'oklog-api/oklog_api_error'
7
+ require 'oklog-api/request'
8
+ require 'oklog-api/api_request'
9
+ require 'oklog-api/response'
10
+
11
+ module OklogApi
12
+ class << self
13
+ def generate_access_token(code=nil)
14
+ if OklogApi.keycloak_grant_type == "password"
15
+ payload = "grant_type=#{OklogApi.keycloak_grant_type}&client_id=#{OklogApi.keycloak_client_id}&username=#{OklogApi.api_user_email}&password=#{OklogApi.api_user_password}"
16
+ else
17
+ payload = "grant_type=#{OklogApi.keycloak_grant_type}&client_id=#{OklogApi.keycloak_client_id}&client_secret=#{OklogApi.keycloak_client_secret}&code=#{code ||OklogApi::Request.access_token}&redirect_uri=#{OklogApi.keycloak_redirect_uri}"
18
+ end
19
+ connection = Faraday.new(OklogApi.keycloak_token_url, proxy: nil,
20
+ ssl: OklogApi::Request.ssl_options || { version: "TLSv1_2" }) do |faraday|
21
+ faraday.adapter Faraday.default_adapter
22
+ faraday.response :logger, ::Logger.new(STDOUT), bodies: true
23
+ end
24
+
25
+ response = connection.post OklogApi.keycloak_token_url, payload do |request|
26
+ request.headers['accept'] = 'application/json'
27
+ end
28
+
29
+ JSON.parse(response.body)
30
+ end
31
+
32
+ def refresh_access_token
33
+ payload = "grant_type=refresh_token&client_id=#{OklogApi.keycloak_client_id}&client_secret=#{OklogApi.keycloak_client_secret}&refresh_token=#{OklogApi::Request.refresh_token}&redirect_uri=#{OklogApi.keycloak_redirect_uri}"
34
+ connection = Faraday.new(OklogApi.keycloak_token_url, proxy: nil,
35
+ ssl: OklogApi::Request.ssl_options || { version: "TLSv1_2" }) do |faraday|
36
+ faraday.adapter Faraday.default_adapter
37
+ faraday.response :logger, ::Logger.new(STDOUT), bodies: true
38
+ end
39
+
40
+ response = connection.post OklogApi.keycloak_token_url, payload do |request|
41
+ request.headers['accept'] = 'application/json'
42
+ end
43
+
44
+ JSON.parse(response.body)
45
+ end
46
+
47
+ def setup
48
+ yield self
49
+ end
50
+
51
+ def register(name, value, type = nil)
52
+ cattr_accessor "#{name}_setting".to_sym
53
+
54
+ add_reader(name)
55
+ add_writer(name, type)
56
+ send "#{name}=", value
57
+ end
58
+
59
+ def add_reader(name)
60
+ define_singleton_method(name) do |*args|
61
+ send("#{name}_setting").value(*args)
62
+ end
63
+ end
64
+
65
+ def add_writer(name, type)
66
+ define_singleton_method("#{name}=") do |value|
67
+ send("#{name}_setting=", DynamicSetting.build(value, type))
68
+ end
69
+ end
70
+ end
71
+
72
+ class DynamicSetting
73
+ def self.build(setting, type)
74
+ (type ? klass(type) : self).new(setting)
75
+ end
76
+
77
+ def self.klass(type)
78
+ klass = "#{type.to_s.camelcase}Setting"
79
+ raise ArgumentError, "Unknown type: #{type}" unless OklogApi.const_defined?(klass)
80
+ OklogApi.const_get(klass)
81
+ end
82
+
83
+ def initialize(setting)
84
+ @setting = setting
85
+ end
86
+
87
+ def value(*_args)
88
+ @setting
89
+ end
90
+ end
91
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oklog-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Pavel Osetrov
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-07-25 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: faraday
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 2.0.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 2.0.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: faraday-gzip
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.1.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 0.1.0
40
+ - !ruby/object:Gem::Dependency
41
+ name: multi_json
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.11.0
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.11.0
54
+ - !ruby/object:Gem::Dependency
55
+ name: irb
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.3.6
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 1.3.6
68
+ - !ruby/object:Gem::Dependency
69
+ name: jwt
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: multipart-post
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: psych
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 4.0.0
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: 4.0.0
110
+ description: ''
111
+ email: p.osetrov@daobit.ru
112
+ executables: []
113
+ extensions: []
114
+ extra_rdoc_files: []
115
+ files:
116
+ - LICENSE
117
+ - README.markdown
118
+ - lib/generators/oklog_api/install/USAGE
119
+ - lib/generators/oklog_api/install/install_generator.rb
120
+ - lib/generators/oklog_api/install/templates/oklog_api.rb
121
+ - lib/generators/oklog_api/install/templates/oklog_api.yml
122
+ - lib/oklog-api.rb
123
+ - lib/oklog-api/api_request.rb
124
+ - lib/oklog-api/rail_locator_api_error.rb
125
+ - lib/oklog-api/request.rb
126
+ - lib/oklog-api/response.rb
127
+ - lib/oklog-api/version.rb
128
+ homepage: https://oklog.ru
129
+ licenses:
130
+ - MIT
131
+ metadata: {}
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '2.5'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubygems_version: 3.6.3
147
+ specification_version: 4
148
+ summary: OkLog API
149
+ test_files: []