crowdin-api 1.1.1 → 1.5.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/.github/workflows/docs.yml +31 -0
- data/.github/workflows/test-and-lint.yml +1 -1
- data/.gitignore +2 -2
- data/.rubocop_todo.yml +114 -48
- data/Gemfile +3 -0
- data/README.md +61 -17
- data/bin/crowdin-console +5 -5
- data/crowdin-api.gemspec +1 -2
- data/lib/crowdin-api/api_resources/bundles.rb +104 -0
- data/lib/crowdin-api/api_resources/dictionaries.rb +32 -0
- data/lib/crowdin-api/api_resources/distributions.rb +92 -0
- data/lib/crowdin-api/api_resources/glossaries.rb +248 -0
- data/lib/crowdin-api/api_resources/labels.rb +98 -0
- data/lib/crowdin-api/api_resources/languages.rb +61 -0
- data/lib/crowdin-api/api_resources/machine_translation_engines.rb +79 -0
- data/lib/crowdin-api/api_resources/projects.rb +151 -0
- data/lib/crowdin-api/api_resources/reports.rb +184 -0
- data/lib/crowdin-api/api_resources/screenshots.rb +172 -0
- data/lib/crowdin-api/api_resources/source_files.rb +305 -0
- data/lib/crowdin-api/{api-resources → api_resources}/source_strings.rb +19 -24
- data/lib/crowdin-api/api_resources/storages.rb +66 -0
- data/lib/crowdin-api/api_resources/string_comments.rb +68 -0
- data/lib/crowdin-api/api_resources/string_translations.rb +193 -0
- data/lib/crowdin-api/api_resources/tasks.rb +102 -0
- data/lib/crowdin-api/api_resources/teams.rb +135 -0
- data/lib/crowdin-api/api_resources/translation_memory.rb +131 -0
- data/lib/crowdin-api/{api-resources → api_resources}/translation_status.rb +24 -30
- data/lib/crowdin-api/{api-resources → api_resources}/translations.rb +41 -59
- data/lib/crowdin-api/api_resources/users.rb +161 -0
- data/lib/crowdin-api/api_resources/vendors.rb +21 -0
- data/lib/crowdin-api/api_resources/webhooks.rb +68 -0
- data/lib/crowdin-api/api_resources/workflows.rb +59 -0
- data/lib/crowdin-api/client/client.rb +155 -47
- data/lib/crowdin-api/client/configuration.rb +16 -12
- data/lib/crowdin-api/client/version.rb +1 -1
- data/lib/crowdin-api/core/errors.rb +3 -1
- data/lib/crowdin-api/core/{api_errors_raiser.rb → errors_raisers.rb} +21 -11
- data/lib/crowdin-api/core/fetch_all_extensions.rb +9 -0
- data/lib/crowdin-api/core/request.rb +50 -90
- data/lib/crowdin-api/core/send_request.rb +67 -0
- data/lib/crowdin-api.rb +21 -11
- data/spec/api_resources/bundles_spec.rb +61 -0
- data/spec/api_resources/dictionaries_spec.rb +23 -0
- data/spec/api_resources/distributions_spec.rb +71 -0
- data/spec/api_resources/glossaries_spec.rb +210 -0
- data/spec/api_resources/labels_spec.rb +71 -0
- data/spec/api_resources/languages_spec.rb +51 -0
- data/spec/api_resources/machine_translation_engines_spec.rb +63 -0
- data/spec/api_resources/projects_spec.rb +215 -0
- data/spec/api_resources/reports_spec.rb +145 -0
- data/spec/api_resources/screenshots_spec.rb +134 -0
- data/spec/api_resources/source_files_spec.rb +184 -0
- data/spec/api_resources/source_strings_spec.rb +51 -0
- data/spec/api_resources/storages_spec.rb +41 -0
- data/spec/api_resources/string_comments_spec.rb +51 -0
- data/spec/api_resources/string_translations_spec.rb +141 -0
- data/spec/api_resources/tasks_spec.rb +79 -0
- data/spec/api_resources/teams_spec.rb +100 -0
- data/spec/api_resources/translation_memory_spec.rb +114 -0
- data/spec/api_resources/translation_status_spec.rb +61 -0
- data/spec/api_resources/translations_spec.rb +107 -0
- data/spec/api_resources/users_spec.rb +117 -0
- data/spec/api_resources/vendors_spec.rb +13 -0
- data/spec/api_resources/webhooks_spec.rb +51 -0
- data/spec/api_resources/workflows_spec.rb +41 -0
- data/spec/spec_helper.rb +23 -2
- data/spec/unit/client_spec.rb +91 -0
- metadata +69 -28
- data/bin/setup +0 -6
- data/lib/crowdin-api/api-resources/languages.rb +0 -81
- data/lib/crowdin-api/api-resources/projects.rb +0 -134
- data/lib/crowdin-api/api-resources/source_files.rb +0 -303
- data/lib/crowdin-api/api-resources/storages.rb +0 -102
- data/lib/crowdin-api/api-resources/workflows.rb +0 -59
- data/spec/core/config-instance_spec.rb +0 -72
- data/spec/crowdin-api_spec.rb +0 -7
|
@@ -1,82 +1,190 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
#
|
|
4
|
-
#
|
|
4
|
+
# A wrapper and interface to the Crowdin API. Please visit the Crowdin developers site
|
|
5
|
+
# for a full explanation of what each of the Crowdin api methods expect and perform.
|
|
5
6
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# require 'crowdin-api'
|
|
9
|
-
#
|
|
10
|
-
# crowdin = Crowdin::Client.new do |config|
|
|
11
|
-
# config.api_token = 'YOUR_API_TOKEN'
|
|
12
|
-
# end
|
|
13
|
-
#
|
|
14
|
-
# crowdin.list_projects
|
|
7
|
+
# https://support.crowdin.com/api/v2/
|
|
8
|
+
# https://support.crowdin.com/enterprise/api/
|
|
15
9
|
#
|
|
16
10
|
module Crowdin
|
|
11
|
+
#
|
|
12
|
+
# === Example
|
|
13
|
+
#
|
|
14
|
+
# require 'crowdin-api'
|
|
15
|
+
#
|
|
16
|
+
# crowdin = Crowdin::Client.new do |config|
|
|
17
|
+
# config.api_token = 'YOUR_API_TOKEN'
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# crowdin.list_projects
|
|
21
|
+
#
|
|
17
22
|
class Client
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
# https://support.crowdin.com/api/v2/
|
|
23
|
-
#
|
|
24
|
-
include ApiResources::Languages
|
|
25
|
-
include ApiResources::Projects
|
|
26
|
-
include ApiResources::SourceFiles
|
|
27
|
-
include ApiResources::Storages
|
|
28
|
-
include ApiResources::TranslationStatus
|
|
29
|
-
include ApiResources::Translations
|
|
30
|
-
include ApiResources::Workflows
|
|
31
|
-
include ApiResources::SourceStrings
|
|
23
|
+
# Processing API Resources modules to include them to the Client
|
|
24
|
+
API_RESOURCES_MODULES.each do |module_name|
|
|
25
|
+
Client.send(:include, Object.const_get("Crowdin::ApiResources::#{module_name}"))
|
|
26
|
+
end
|
|
32
27
|
|
|
33
|
-
include
|
|
28
|
+
# Processing Error Raisers modules to include them to the Client
|
|
29
|
+
ERROR_RAISERS_MODULES.each do |module_name|
|
|
30
|
+
Client.send(:include, Object.const_get("Crowdin::Errors::#{module_name}"))
|
|
31
|
+
end
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
include Web::FetchAllExtensions
|
|
36
34
|
|
|
35
|
+
# Config instance that includes configuration options for the Client
|
|
37
36
|
attr_reader :config
|
|
37
|
+
# Instance with established connection through RestClient to the Crowdin API
|
|
38
38
|
attr_reader :connection
|
|
39
|
+
# Instance with options and headers for RestClient connection
|
|
39
40
|
attr_reader :options
|
|
41
|
+
# Logger instance
|
|
42
|
+
attr_reader :logger
|
|
40
43
|
|
|
41
44
|
def initialize(&block)
|
|
42
45
|
build_configuration(&block)
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
update_logger
|
|
48
|
+
update_rest_client_proxy
|
|
46
49
|
|
|
47
50
|
build_connection
|
|
48
51
|
end
|
|
49
52
|
|
|
50
|
-
def log
|
|
51
|
-
!
|
|
53
|
+
def log(message)
|
|
54
|
+
!logger_enabled? || logger.debug(message)
|
|
52
55
|
end
|
|
53
56
|
|
|
54
|
-
|
|
57
|
+
def logger=(logger)
|
|
58
|
+
raise_logger_are_not_enabled_error unless logger_enabled?
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
yield config if block_given?
|
|
60
|
+
@logger = logger
|
|
61
|
+
update_rest_client_logger
|
|
59
62
|
end
|
|
60
63
|
|
|
61
|
-
def
|
|
62
|
-
|
|
64
|
+
def enterprise_mode?
|
|
65
|
+
!!config.organization_domain
|
|
63
66
|
end
|
|
64
67
|
|
|
65
|
-
def
|
|
66
|
-
|
|
68
|
+
def logger_enabled?
|
|
69
|
+
config.logger_enabled?
|
|
67
70
|
end
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
#
|
|
73
|
+
# FetchAll options:
|
|
74
|
+
# * limit, Integer, default: 500 | How many records need to load per one request
|
|
75
|
+
# * offset, Integer, default: 0 | How many records need to skip
|
|
76
|
+
# * request_delay, Integer (seconds), default: 0 | Delay between requests
|
|
77
|
+
#
|
|
78
|
+
#
|
|
79
|
+
# Note: Please, specify project_id while Client initialization if you need to use methods that need it within FetchAll
|
|
80
|
+
#
|
|
81
|
+
# === Example
|
|
82
|
+
#
|
|
83
|
+
# @crowdin.fetch_all(:list_projects)
|
|
84
|
+
#
|
|
85
|
+
# with specified options
|
|
86
|
+
#
|
|
87
|
+
# @crowdin.fetch_all(:list_projects, { limit: 10, request_delay: 1 })
|
|
88
|
+
#
|
|
89
|
+
# playing with response per fetch. Note: the block actually don't make any effect to finite result
|
|
90
|
+
#
|
|
91
|
+
# @crowdin.fetch_all(:list_projects, { limit: 10, request_delay: 1 }) { |response| puts response['data'] }
|
|
92
|
+
#
|
|
93
|
+
# also you can specify retry configuration to handle some exceptions
|
|
94
|
+
#
|
|
95
|
+
# Retry configuration options:
|
|
96
|
+
# * request_delay, Integer (seconds), default: 0 | Delay between retries
|
|
97
|
+
# * retries_count, Integer, default: 0
|
|
98
|
+
# * error_messages, Array
|
|
99
|
+
#
|
|
100
|
+
# @crowdin.fetch_all(:list_projects, {}, { request_delay: 2, retries_count: 3, error_messages: ['401'] })
|
|
101
|
+
#
|
|
102
|
+
# fetch all execution will be terminated if response error are same as in error_messages array
|
|
103
|
+
# otherwise system will retry so many times, as indicated at tries_count
|
|
104
|
+
#
|
|
105
|
+
def fetch_all(api_resource, opts = {}, retry_opts = {})
|
|
106
|
+
unless api_resource.to_s.start_with?('list_')
|
|
107
|
+
raise(Errors::FetchAllProcessingError, "#{api_resource} method aren't supported for FetchAll")
|
|
108
|
+
end
|
|
73
109
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
110
|
+
limit = opts[:limit] || Web::FetchAllExtensions::MAX_ITEMS_COUNT_PER_REQUEST
|
|
111
|
+
offset = opts[:offset] || 0
|
|
112
|
+
request_delay = opts[:request_delay] || 0
|
|
77
113
|
|
|
78
|
-
|
|
79
|
-
|
|
114
|
+
retry_request_delay = retry_opts[:request_delay] || 0
|
|
115
|
+
retries_count = retry_opts[:retries_count] || 0
|
|
116
|
+
retry_error_messages = retry_opts[:error_messages] || []
|
|
117
|
+
|
|
118
|
+
result = []
|
|
119
|
+
loop do
|
|
120
|
+
response = case api_resource
|
|
121
|
+
when :list_terms
|
|
122
|
+
send(api_resource, opts[:glossary_id], { limit: limit, offset: offset }.merge(opts))
|
|
123
|
+
when :list_file_revisions
|
|
124
|
+
send(api_resource, opts[:file_id], { limit: limit, offset: offset }.merge(opts))
|
|
125
|
+
else
|
|
126
|
+
send(api_resource, { limit: limit, offset: offset }.merge(opts))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
if response.is_a?(String) && response.match('Something went wrong')
|
|
130
|
+
if retries_count.positive?
|
|
131
|
+
retry_error_messages.each do |message|
|
|
132
|
+
break if response.match(message)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
retries_count -= 1
|
|
136
|
+
sleep retry_request_delay
|
|
137
|
+
else
|
|
138
|
+
raise(Errors::FetchAllProcessingError, response)
|
|
139
|
+
end
|
|
140
|
+
else
|
|
141
|
+
yield response if block_given?
|
|
142
|
+
deserialized_response = response['data']
|
|
143
|
+
result.concat(deserialized_response)
|
|
144
|
+
offset += deserialized_response.size
|
|
145
|
+
break if deserialized_response.size < limit
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
sleep request_delay
|
|
149
|
+
end
|
|
150
|
+
result
|
|
151
|
+
rescue StandardError => e
|
|
152
|
+
raise(Errors::FetchAllProcessingError, "FetchAll wasn't processed. Details - #{e.message}")
|
|
80
153
|
end
|
|
154
|
+
|
|
155
|
+
private
|
|
156
|
+
|
|
157
|
+
def build_configuration
|
|
158
|
+
@config = Crowdin::Configuration.new
|
|
159
|
+
yield config if block_given?
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def build_connection
|
|
163
|
+
build_options
|
|
164
|
+
@connection ||= ::RestClient::Resource.new(config.base_url, options)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def build_options
|
|
168
|
+
@options ||= config.options.merge(headers: config.headers)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def set_default_logger
|
|
172
|
+
require 'logger'
|
|
173
|
+
|
|
174
|
+
@logger ||= Logger.new($stdout)
|
|
175
|
+
update_rest_client_logger
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def update_rest_client_logger
|
|
179
|
+
::RestClient.log = @logger
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def update_rest_client_proxy
|
|
183
|
+
ENV['http_proxy'] ? ::RestClient.proxy = ENV.fetch('http_proxy') : false
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def update_logger
|
|
187
|
+
config.logger_enabled? ? set_default_logger : config.enable_logger = false
|
|
188
|
+
end
|
|
81
189
|
end
|
|
82
190
|
end
|
|
@@ -5,13 +5,12 @@ module Crowdin
|
|
|
5
5
|
attr_accessor :api_token
|
|
6
6
|
attr_accessor :project_id
|
|
7
7
|
attr_accessor :organization_domain
|
|
8
|
+
|
|
8
9
|
attr_accessor :enable_logger
|
|
10
|
+
alias logger_enabled? enable_logger
|
|
9
11
|
|
|
10
12
|
attr_reader :target_api_url
|
|
11
13
|
|
|
12
|
-
alias logger_enabled? enable_logger
|
|
13
|
-
alias enterprise_mode? organization_domain
|
|
14
|
-
|
|
15
14
|
def initialize
|
|
16
15
|
@target_api_url = '/api/v2'
|
|
17
16
|
end
|
|
@@ -20,25 +19,30 @@ module Crowdin
|
|
|
20
19
|
{
|
|
21
20
|
headers: {},
|
|
22
21
|
timeout: nil,
|
|
23
|
-
json:
|
|
22
|
+
json: true
|
|
24
23
|
}
|
|
25
24
|
end
|
|
26
25
|
|
|
27
26
|
def headers
|
|
28
27
|
{
|
|
29
|
-
'Accept'
|
|
28
|
+
'Accept' => 'application/json',
|
|
30
29
|
'Authorization' => "Bearer #{api_token}",
|
|
31
|
-
'Content-Type'
|
|
32
|
-
'User-Agent'
|
|
30
|
+
'Content-Type' => 'application/json',
|
|
31
|
+
'User-Agent' => "crowdin-rb/#{Crowdin::Client::VERSION}/#{RUBY_VERSION}/#{RUBY_PLATFORM}"
|
|
33
32
|
}
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
def base_url
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
@base_url ||=
|
|
37
|
+
if !!organization_domain
|
|
38
|
+
if organization_domain.include?('.com')
|
|
39
|
+
"https://#{organization_domain}"
|
|
40
|
+
else
|
|
41
|
+
"https://#{organization_domain}.api.crowdin.com"
|
|
42
|
+
end
|
|
43
|
+
else
|
|
44
|
+
'https://api.crowdin.com'
|
|
45
|
+
end
|
|
42
46
|
end
|
|
43
47
|
end
|
|
44
48
|
end
|
|
@@ -2,9 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
module Crowdin
|
|
4
4
|
module Errors
|
|
5
|
+
# Client errors raiser
|
|
6
|
+
module ClientErrorsRaiser
|
|
7
|
+
def raise_logger_are_not_enabled_error
|
|
8
|
+
raise(LoggerAreNotEnabledError, 'Logger are not enabled in your Client configuration, enable it ' \
|
|
9
|
+
'before setting your logger')
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Command-Line Client errors raiser
|
|
14
|
+
module ClcErrorsRaiser
|
|
15
|
+
def raise_api_token_is_required_error
|
|
16
|
+
raise(ArgumentError, '--api-token option is required')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def raise_organization_domain_is_required_error
|
|
20
|
+
raise(ArgumentError, '--organization-domain option is required for Enterprise mode')
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# API errors raiser
|
|
5
25
|
module ApiErrorsRaiser
|
|
6
26
|
def raise_only_for_enterprise_mode_error
|
|
7
|
-
raise(
|
|
27
|
+
raise(OnlyForEnterpriseModeError, 'This method can be called only for Enterprise mode')
|
|
8
28
|
end
|
|
9
29
|
|
|
10
30
|
def raise_project_id_is_required_error
|
|
@@ -14,16 +34,6 @@ module Crowdin
|
|
|
14
34
|
def raise_parameter_is_required_error(parameter)
|
|
15
35
|
raise(ArgumentError, ":#{parameter} is required")
|
|
16
36
|
end
|
|
17
|
-
|
|
18
|
-
# crowdin-console errors
|
|
19
|
-
|
|
20
|
-
def raise_api_token_is_required_error
|
|
21
|
-
raise(ArgumentError, '--api-token option is required')
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def raise_organization_domain_is_required_error
|
|
25
|
-
raise(ArgumentError, '--organization-domain option is required for Enterprise mode')
|
|
26
|
-
end
|
|
27
37
|
end
|
|
28
38
|
end
|
|
29
39
|
end
|
|
@@ -3,116 +3,76 @@
|
|
|
3
3
|
module Crowdin
|
|
4
4
|
module Web
|
|
5
5
|
class Request
|
|
6
|
-
attr_reader :
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@
|
|
12
|
-
@
|
|
13
|
-
@
|
|
14
|
-
@destination = destination
|
|
15
|
-
@errors = []
|
|
6
|
+
attr_reader :connection
|
|
7
|
+
attr_reader :method
|
|
8
|
+
attr_reader :payload
|
|
9
|
+
|
|
10
|
+
def initialize(connection, method, url, payload = {})
|
|
11
|
+
@connection = connection[url]
|
|
12
|
+
@method = method
|
|
13
|
+
@payload = build_payload(payload)
|
|
16
14
|
end
|
|
17
15
|
|
|
18
|
-
def
|
|
19
|
-
|
|
20
|
-
process_response!
|
|
16
|
+
def get?
|
|
17
|
+
method.eql?(:get)
|
|
21
18
|
end
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def process_request!
|
|
26
|
-
return @response = client.connection[@full_path].delete if delete_request?
|
|
27
|
-
return @response = client.connection[@full_path].get(@payload) if get_request?
|
|
28
|
-
|
|
29
|
-
client.connection[@full_path].send(@method, @payload, @headers) { |response, _, _| @response = response }
|
|
30
|
-
rescue StandardError => error
|
|
31
|
-
client.log! error
|
|
32
|
-
|
|
33
|
-
@errors << "Something went wrong while proccessing request. Details - #{error.class}"
|
|
20
|
+
def get
|
|
21
|
+
connection.get(prepare_payload(payload[:params]))
|
|
34
22
|
end
|
|
35
23
|
|
|
36
|
-
def
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
begin
|
|
40
|
-
if @response
|
|
41
|
-
client.log! "args: #{@response.request.args}"
|
|
42
|
-
|
|
43
|
-
if @response.body.empty?
|
|
44
|
-
@response.code
|
|
45
|
-
else
|
|
46
|
-
doc = JSON.parse(@response.body)
|
|
47
|
-
|
|
48
|
-
client.log! "body: #{doc}"
|
|
49
|
-
|
|
50
|
-
data = fetch_response_data(doc)
|
|
51
|
-
|
|
52
|
-
@errors.any? ? fetch_errors : data
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
rescue StandardError => error
|
|
56
|
-
client.log! error
|
|
57
|
-
|
|
58
|
-
@errors << "Something went wrong while proccessing response. Details - #{error.class}"
|
|
59
|
-
|
|
60
|
-
fetch_errors
|
|
61
|
-
end
|
|
24
|
+
def delete?
|
|
25
|
+
method.eql?(:delete)
|
|
62
26
|
end
|
|
63
27
|
|
|
64
|
-
def
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
get_request? ? { params: fetch_cleared_query(query) } : fetch_cleared_query(query).to_json
|
|
28
|
+
def delete
|
|
29
|
+
connection.delete
|
|
68
30
|
end
|
|
69
31
|
|
|
70
|
-
def
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
.match(/filename=("?)(.+)\1/)[2]
|
|
74
|
-
|
|
75
|
-
IO.copy_stream(download, destination)
|
|
76
|
-
|
|
77
|
-
destination
|
|
78
|
-
rescue StandardError => error
|
|
79
|
-
client.log! error
|
|
32
|
+
def process_with_body
|
|
33
|
+
connection.send(method, prepare_payload(payload[:params]), payload[:headers]) { |response, _, _| response }
|
|
34
|
+
end
|
|
80
35
|
|
|
81
|
-
|
|
36
|
+
def post?
|
|
37
|
+
method.eql?(:post)
|
|
82
38
|
end
|
|
39
|
+
alias post process_with_body
|
|
83
40
|
|
|
84
|
-
def
|
|
85
|
-
|
|
41
|
+
def patch?
|
|
42
|
+
method.eql?(:patch)
|
|
86
43
|
end
|
|
44
|
+
alias patch process_with_body
|
|
87
45
|
|
|
88
|
-
def
|
|
89
|
-
|
|
90
|
-
download_file(doc['data']['url'])
|
|
91
|
-
else
|
|
92
|
-
doc
|
|
93
|
-
end
|
|
46
|
+
def put?
|
|
47
|
+
method.eql?(:put)
|
|
94
48
|
end
|
|
49
|
+
alias put process_with_body
|
|
95
50
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
query.reject { |_, value| value.nil? }
|
|
104
|
-
else
|
|
105
|
-
query
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def build_payload(payload)
|
|
54
|
+
%i[params headers].each do |key|
|
|
55
|
+
payload[key] ||= {}
|
|
56
|
+
end
|
|
57
|
+
payload
|
|
106
58
|
end
|
|
107
|
-
end
|
|
108
59
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
end
|
|
60
|
+
def prepare_payload(params)
|
|
61
|
+
return params if params.is_a?(File)
|
|
112
62
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
63
|
+
get? ? { params: fetch_cleared_params(params) } : fetch_cleared_params(params).to_json
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def fetch_cleared_params(params)
|
|
67
|
+
case params
|
|
68
|
+
when Array
|
|
69
|
+
params.map { |el| el.reject { |_, value| value.nil? } }.reject(&:empty?)
|
|
70
|
+
when Hash
|
|
71
|
+
params.reject { |_, value| value.nil? }
|
|
72
|
+
else
|
|
73
|
+
params
|
|
74
|
+
end
|
|
75
|
+
end
|
|
116
76
|
end
|
|
117
77
|
end
|
|
118
78
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Crowdin
|
|
4
|
+
module Web
|
|
5
|
+
class SendRequest
|
|
6
|
+
attr_reader :request
|
|
7
|
+
|
|
8
|
+
def initialize(request, file_destination = nil)
|
|
9
|
+
@request = request
|
|
10
|
+
@file_destination = file_destination
|
|
11
|
+
@errors = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def perform
|
|
15
|
+
parse_response(process_request)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def process_request
|
|
21
|
+
request.send(request.method)
|
|
22
|
+
rescue StandardError => e
|
|
23
|
+
@errors << "Something went wrong while request processing. Details - #{e.message}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def parse_response(response)
|
|
27
|
+
return @errors.join('; ') if @errors.any?
|
|
28
|
+
|
|
29
|
+
begin
|
|
30
|
+
if response
|
|
31
|
+
if response.body.empty?
|
|
32
|
+
response.code
|
|
33
|
+
else
|
|
34
|
+
parsed_body = JSON.parse(response.body)
|
|
35
|
+
parsed_response = fetch_response_data(parsed_body)
|
|
36
|
+
|
|
37
|
+
@errors.any? ? @errors.join('; ') : parsed_response
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
@errors << "Something went wrong while response processing. Details - #{e.message}"
|
|
42
|
+
@errors.join('; ')
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def fetch_response_data(doc)
|
|
47
|
+
if doc['data'].is_a?(Hash) && doc['data']['url'] && doc['data']['url'].include?('response-content-disposition')
|
|
48
|
+
download_file(doc['data']['url'])
|
|
49
|
+
else
|
|
50
|
+
doc
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def download_file(url)
|
|
55
|
+
download = URI.parse(url).open
|
|
56
|
+
destination = @file_destination || download.meta['content-disposition']
|
|
57
|
+
.match(/filename=("?)(.+)\1/)[2]
|
|
58
|
+
|
|
59
|
+
IO.copy_stream(download, destination)
|
|
60
|
+
|
|
61
|
+
destination
|
|
62
|
+
rescue StandardError => e
|
|
63
|
+
@errors << "Something went wrong while downloading file. Details - #{e.message}"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/lib/crowdin-api.rb
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
module Crowdin
|
|
4
|
+
# API Resources modules
|
|
5
|
+
API_RESOURCES_MODULES = %i[Storages Languages Projects Workflows SourceFiles Translations SourceStrings
|
|
6
|
+
StringTranslations StringComments Screenshots Glossaries TranslationMemory
|
|
7
|
+
MachineTranslationEngines Reports Tasks Users Teams Vendors Webhooks
|
|
8
|
+
Dictionaries Distributions Labels TranslationStatus Bundles].freeze
|
|
9
|
+
|
|
10
|
+
# Error Raisers modules
|
|
11
|
+
ERROR_RAISERS_MODULES = %i[ApiErrorsRaiser ClientErrorsRaiser].freeze
|
|
12
|
+
end
|
|
13
|
+
|
|
3
14
|
# Libs
|
|
4
15
|
require 'json'
|
|
5
16
|
require 'open-uri'
|
|
@@ -7,20 +18,19 @@ require 'rest-client'
|
|
|
7
18
|
|
|
8
19
|
# Core modules
|
|
9
20
|
require 'crowdin-api/core/errors'
|
|
10
|
-
require 'crowdin-api/core/
|
|
21
|
+
require 'crowdin-api/core/errors_raisers'
|
|
11
22
|
require 'crowdin-api/core/request'
|
|
23
|
+
require 'crowdin-api/core/send_request'
|
|
24
|
+
require 'crowdin-api/core/fetch_all_extensions'
|
|
12
25
|
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
require
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
require 'crowdin-api/api-resources/translations'
|
|
20
|
-
require 'crowdin-api/api-resources/workflows'
|
|
21
|
-
require 'crowdin-api/api-resources/source_strings'
|
|
26
|
+
# API modules
|
|
27
|
+
Crowdin::API_RESOURCES_MODULES.each do |api_resource|
|
|
28
|
+
require "crowdin-api/api_resources/#{api_resource.to_s.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase}"
|
|
29
|
+
rescue LoadError
|
|
30
|
+
# Ignored
|
|
31
|
+
end
|
|
22
32
|
|
|
23
|
-
# Client
|
|
33
|
+
# Client modules
|
|
24
34
|
require 'crowdin-api/client/version'
|
|
25
35
|
require 'crowdin-api/client/configuration'
|
|
26
36
|
require 'crowdin-api/client/client'
|