crowdin-api 0.5.0 → 1.1.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 (38) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/build-and-publish.yml +30 -0
  3. data/.github/workflows/test-and-lint.yml +31 -0
  4. data/.gitignore +12 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +5 -0
  7. data/.rubocop_todo.yml +139 -0
  8. data/CODE_OF_CONDUCT.md +128 -0
  9. data/CONTRIBUTING.md +71 -0
  10. data/Gemfile +5 -0
  11. data/LICENSE +1 -1
  12. data/README.md +114 -267
  13. data/Rakefile +19 -0
  14. data/bin/crowdin-console +54 -0
  15. data/bin/setup +6 -0
  16. data/crowdin-api.gemspec +33 -0
  17. data/lib/crowdin-api/api-resources/languages.rb +81 -0
  18. data/lib/crowdin-api/api-resources/projects.rb +134 -0
  19. data/lib/crowdin-api/api-resources/source_files.rb +303 -0
  20. data/lib/crowdin-api/api-resources/source_strings.rb +74 -0
  21. data/lib/crowdin-api/api-resources/storages.rb +102 -0
  22. data/lib/crowdin-api/api-resources/translation_status.rb +89 -0
  23. data/lib/crowdin-api/api-resources/translations.rb +162 -0
  24. data/lib/crowdin-api/api-resources/workflows.rb +59 -0
  25. data/lib/crowdin-api/client/client.rb +82 -0
  26. data/lib/crowdin-api/client/configuration.rb +44 -0
  27. data/lib/crowdin-api/client/version.rb +7 -0
  28. data/lib/crowdin-api/core/api_errors_raiser.rb +29 -0
  29. data/lib/crowdin-api/core/errors.rb +7 -0
  30. data/lib/crowdin-api/core/request.rb +118 -0
  31. data/lib/crowdin-api.rb +23 -126
  32. data/spec/core/config-instance_spec.rb +72 -0
  33. data/spec/crowdin-api_spec.rb +7 -0
  34. data/spec/spec_helper.rb +9 -0
  35. metadata +112 -40
  36. data/lib/crowdin-api/errors.rb +0 -23
  37. data/lib/crowdin-api/methods.rb +0 -427
  38. data/lib/crowdin-api/version.rb +0 -5
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Crowdin
4
+ module ApiResources
5
+ module Translations
6
+ def pre_translation_status(pre_translation_id = nil, project_id = config.project_id)
7
+ pre_translation_id || raise_parameter_is_required_error(:pre_translation_id)
8
+ project_id || raise_project_id_is_required_error
9
+
10
+ request = Web::Request.new(
11
+ self,
12
+ :get,
13
+ "/projects/#{project_id}/pre-translations/#{pre_translation_id}"
14
+ )
15
+
16
+ request.perform
17
+ end
18
+
19
+ def apply_pre_translation(query = {}, project_id = config.project_id)
20
+ project_id || raise_project_id_is_required_error
21
+
22
+ request = Web::Request.new(
23
+ self,
24
+ :post,
25
+ "/projects/#{project_id}/pre-translations",
26
+ query
27
+ )
28
+
29
+ request.perform
30
+ end
31
+
32
+ def build_project_directory_translation(directory_id = nil, query = {}, project_id = config.project_id)
33
+ directory_id || raise_parameter_is_required_error(:directory_id)
34
+ project_id || raise_project_id_is_required_error
35
+
36
+ request = Web::Request.new(
37
+ self,
38
+ :post,
39
+ "/projects/#{project_id}/translations/builds/directories/#{directory_id}",
40
+ query
41
+ )
42
+
43
+ request.perform
44
+ end
45
+
46
+ def build_project_file_translation(file_id = nil, query = {}, project_id = config.project_id)
47
+ file_id || raise_parameter_is_required_error(:file_id)
48
+ project_id || raise_project_id_is_required_error
49
+
50
+ headers = query[:eTag] ? { 'If-None-Match' => query[:eTag] } : {}
51
+
52
+ request = Web::Request.new(
53
+ self,
54
+ :post,
55
+ "/projects/#{project_id}/translations/builds/files/#{file_id}",
56
+ query,
57
+ headers
58
+ )
59
+
60
+ request.perform
61
+ end
62
+
63
+ def list_project_builds(query = {}, project_id = config.project_id)
64
+ project_id || raise_project_id_is_required_error
65
+
66
+ request = Web::Request.new(
67
+ self,
68
+ :get,
69
+ "/projects/#{project_id}/translations/builds",
70
+ query
71
+ )
72
+
73
+ request.perform
74
+ end
75
+
76
+ def build_project_translation(query = {}, project_id = config.project_id)
77
+ project_id || raise_project_id_is_required_error
78
+
79
+ request = Web::Request.new(
80
+ self,
81
+ :post,
82
+ "/projects/#{project_id}/translations/builds",
83
+ query
84
+ )
85
+
86
+ request.perform
87
+ end
88
+
89
+ def upload_translations(language_id = nil, query = {}, project_id = config.project_id)
90
+ language_id || raise_parameter_is_required_error(:language_id)
91
+ project_id || raise_project_id_is_required_error
92
+
93
+ request = Web::Request.new(
94
+ self,
95
+ :post,
96
+ "/projects/#{project_id}/translations/#{language_id}",
97
+ query
98
+ )
99
+
100
+ request.perform
101
+ end
102
+
103
+ def download_project_translations(build_id = nil, destination = nil, project_id = config.project_id)
104
+ destination || raise_parameter_is_required_error(:destination)
105
+ build_id || raise_parameter_is_required_error(:build_id)
106
+ project_id || raise_project_id_is_required_error
107
+
108
+ request = Web::Request.new(
109
+ self,
110
+ :get,
111
+ "/projects/#{project_id}/translations/builds/#{build_id}/download",
112
+ {},
113
+ {},
114
+ destination
115
+ )
116
+
117
+ request.perform
118
+ end
119
+
120
+ def check_project_build_status(build_id = nil, project_id = config.project_id)
121
+ build_id || raise_parameter_is_required_error(:build_id)
122
+ project_id || raise_project_id_is_required_error
123
+
124
+ request = Web::Request.new(
125
+ self,
126
+ :get,
127
+ "/projects/#{project_id}/translations/builds/#{build_id}"
128
+ )
129
+
130
+ request.perform
131
+ end
132
+
133
+ def cancel_build(build_id = nil, project_id = config.project_id)
134
+ build_id || raise_parameter_is_required_error(:build_id)
135
+ project_id || raise_project_id_is_required_error
136
+
137
+ request = Web::Request.new(
138
+ self,
139
+ :delete,
140
+ "/projects/#{project_id}/translations/builds/#{build_id}"
141
+ )
142
+
143
+ request.perform
144
+ end
145
+
146
+ def export_project_translation(query = {}, destination = nil, project_id = config.project_id)
147
+ project_id || raise_project_id_is_required_error
148
+
149
+ request = Web::Request.new(
150
+ self,
151
+ :post,
152
+ "/projects/#{project_id}/translations/exports",
153
+ query,
154
+ {},
155
+ destination
156
+ )
157
+
158
+ request.perform
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Crowdin
4
+ module ApiResources
5
+ module Workflows
6
+ def list_workflow_steps(query = {}, project_id = config.project_id)
7
+ config.enterprise_mode? || raise_only_for_enterprise_mode_error
8
+ project_id || raise_project_id_is_required_error
9
+
10
+ request = Web::Request.new(
11
+ self,
12
+ :get,
13
+ "/projects/#{project_id}/workflow-steps",
14
+ query
15
+ )
16
+
17
+ request.perform
18
+ end
19
+
20
+ def get_workflow_step(step_id = nil, project_id = config.project_id)
21
+ config.enterprise_mode? || raise_only_for_enterprise_mode_error
22
+ step_id || raise_parameter_is_required_error(:step_id)
23
+ project_id || raise_project_id_is_required_error
24
+
25
+ request = Web::Request.new(
26
+ self,
27
+ :get,
28
+ "/projects/#{project_id}/workflow-steps/#{step_id}"
29
+ )
30
+
31
+ request.perform
32
+ end
33
+
34
+ def list_workflow_templates(query = {})
35
+ request = Web::Request.new(
36
+ self,
37
+ :get,
38
+ '/workflow-templates',
39
+ query
40
+ )
41
+
42
+ request.perform
43
+ end
44
+
45
+ def get_workflow_template(template_id = nil)
46
+ config.enterprise_mode? || raise_only_for_enterprise_mode_error
47
+ template_id || raise_parameter_is_required_error(:template_id)
48
+
49
+ request = Web::Request.new(
50
+ self,
51
+ :get,
52
+ "/workflow-templates/#{template_id}"
53
+ )
54
+
55
+ request.perform
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # The Crowdin::Client library is used for interactions with a crowdin.com website.
5
+ #
6
+ # == Example
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
15
+ #
16
+ module Crowdin
17
+ class Client
18
+ # A wrapper and interface to the Crowdin api. Please visit the Crowdin developers
19
+ # site for a full explanation of what each of the Crowdin api methods
20
+ # expect and perform.
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
32
+
33
+ include Errors::ApiErrorsRaiser
34
+
35
+ attr_accessor :logger
36
+
37
+ attr_reader :config
38
+ attr_reader :connection
39
+ attr_reader :options
40
+
41
+ def initialize(&block)
42
+ build_configuration(&block)
43
+
44
+ check_logger
45
+ check_rest_client_proxy
46
+
47
+ build_connection
48
+ end
49
+
50
+ def log!(message)
51
+ !config.logger_enabled? || logger.debug(message)
52
+ end
53
+
54
+ private
55
+
56
+ def build_configuration
57
+ @config = Crowdin::Configuration.new
58
+ yield config if block_given?
59
+ end
60
+
61
+ def build_connection
62
+ @connection ||= ::RestClient::Resource.new(config.base_url, build_options)
63
+ end
64
+
65
+ def build_options
66
+ @options ||= config.options.merge(headers: config.headers)
67
+ end
68
+
69
+ def set_default_logger
70
+ require 'logger'
71
+ @logger ||= Logger.new($stderr)
72
+ end
73
+
74
+ def check_rest_client_proxy
75
+ ENV['http_proxy'] ? ::RestClient.proxy = ENV['http_proxy'] : false
76
+ end
77
+
78
+ def check_logger
79
+ config.logger_enabled? ? set_default_logger : config.enable_logger = false
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Crowdin
4
+ class Configuration
5
+ attr_accessor :api_token
6
+ attr_accessor :project_id
7
+ attr_accessor :organization_domain
8
+ attr_accessor :enable_logger
9
+
10
+ attr_reader :target_api_url
11
+
12
+ alias logger_enabled? enable_logger
13
+ alias enterprise_mode? organization_domain
14
+
15
+ def initialize
16
+ @target_api_url = '/api/v2'
17
+ end
18
+
19
+ def options
20
+ {
21
+ headers: {},
22
+ timeout: nil,
23
+ json: true
24
+ }
25
+ end
26
+
27
+ def headers
28
+ {
29
+ 'Accept' => 'application/json',
30
+ 'Authorization' => "Bearer #{api_token}",
31
+ 'Content-Type' => 'application/json',
32
+ 'User-Agent' => "crowdin-rb/#{Crowdin::Client::VERSION}/#{RUBY_VERSION}/#{RUBY_PLATFORM}"
33
+ }
34
+ end
35
+
36
+ def base_url
37
+ if enterprise_mode?
38
+ organization_domain.include?('.com') ? organization_domain : "https://#{organization_domain}.api.crowdin.com"
39
+ else
40
+ 'https://api.crowdin.com'
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Crowdin
4
+ class Client
5
+ VERSION = '1.1.1'
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Crowdin
4
+ module Errors
5
+ module ApiErrorsRaiser
6
+ def raise_only_for_enterprise_mode_error
7
+ raise(OnlyForEnterpriseMode, 'This method can be called only for Enterprise mode')
8
+ end
9
+
10
+ def raise_project_id_is_required_error
11
+ raise(ArgumentError, ':project_id is required in parameters or while Client initialization')
12
+ end
13
+
14
+ def raise_parameter_is_required_error(parameter)
15
+ raise(ArgumentError, ":#{parameter} is required")
16
+ 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
+ end
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Crowdin
4
+ module Errors
5
+ class OnlyForEnterpriseMode < StandardError; end
6
+ end
7
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Crowdin
4
+ module Web
5
+ class Request
6
+ attr_reader :client
7
+
8
+ def initialize(client, method, path, query = {}, headers = {}, destination = nil)
9
+ @client = client
10
+ @method = method
11
+ @full_path = client.config.target_api_url + path
12
+ @payload = perform_payload(query)
13
+ @headers = headers
14
+ @destination = destination
15
+ @errors = []
16
+ end
17
+
18
+ def perform
19
+ process_request!
20
+ process_response!
21
+ end
22
+
23
+ private
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}"
34
+ end
35
+
36
+ def process_response!
37
+ return fetch_errors if @errors.any?
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
62
+ end
63
+
64
+ def perform_payload(query)
65
+ return query if query.is_a?(File)
66
+
67
+ get_request? ? { params: fetch_cleared_query(query) } : fetch_cleared_query(query).to_json
68
+ end
69
+
70
+ def download_file(url)
71
+ download = URI.parse(url).open
72
+ destination = @destination || download.meta['content-disposition']
73
+ .match(/filename=("?)(.+)\1/)[2]
74
+
75
+ IO.copy_stream(download, destination)
76
+
77
+ destination
78
+ rescue StandardError => error
79
+ client.log! error
80
+
81
+ @errors << "Something went wrong while downloading file. Details - #{error.class}"
82
+ end
83
+
84
+ def fetch_errors
85
+ @errors.join(';')
86
+ end
87
+
88
+ def fetch_response_data(doc)
89
+ if doc['data'].is_a?(Hash) && doc['data']['url'] && doc['data']['url'].include?('response-content-disposition')
90
+ download_file(doc['data']['url'])
91
+ else
92
+ doc
93
+ end
94
+ end
95
+
96
+ def fetch_cleared_query(query)
97
+ case query
98
+ when Array
99
+ query.map do |el|
100
+ el.reject { |_, value| value.nil? }
101
+ end.reject(&:empty?)
102
+ when Hash
103
+ query.reject { |_, value| value.nil? }
104
+ else
105
+ query
106
+ end
107
+ end
108
+
109
+ def get_request?
110
+ @method.eql?(:get)
111
+ end
112
+
113
+ def delete_request?
114
+ @method.eql?(:delete)
115
+ end
116
+ end
117
+ end
118
+ end
data/lib/crowdin-api.rb CHANGED
@@ -1,129 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Libs
1
4
  require 'json'
5
+ require 'open-uri'
2
6
  require 'rest-client'
3
- # require 'byebug'
4
-
5
- require "crowdin-api/errors"
6
- require "crowdin-api/methods"
7
- require "crowdin-api/version"
8
-
9
-
10
- # The Crowdin::API library is used for interactions with a crowdin.com website.
11
- #
12
- # == Example
13
- #
14
- # require 'crowdin-api'
15
- # require 'logger'
16
- #
17
- # crowdin = Crowdin::API.new(:api_key => API_KEY, :project_id => PROJECT_ID)
18
- # crowdin.log = Logger.new($stderr)
19
- #
20
- module Crowdin
21
- class API
22
-
23
- class << self
24
- # Default logger for all Crowdin::API instances
25
- #
26
- # Crowdin::API.log = Logger.new($stderr)
27
- #
28
- attr_accessor :log
29
- end
30
-
31
- # Create a new API object using the given parameters.
32
- #
33
- # @param [String] api_key the authentication API key can be found on the project settings page
34
- # @param [String] project_id the project identifier.
35
- # @param [String] account_key the account API Key
36
- # @param [String] base_url the url of the Crowdin API
37
- #
38
- def initialize(options = {})
39
- @api_key = options.delete(:api_key)
40
- @project_id = options.delete(:project_id)
41
- @account_key = options.delete(:account_key)
42
- @base_url = options.delete(:base_url) || 'https://api.crowdin.com'
43
-
44
- @log = nil
45
-
46
- options = {
47
- :headers => {},
48
- :params => {},
49
- :timeout => nil,
50
- :key => @api_key,
51
- :'account-key' => @account_key,
52
- :json => true
53
- }.merge(options)
54
-
55
- options[:headers] = {
56
- 'Accept' => 'application/json',
57
- 'User-Agent' => "crowdin-rb/#{Crowdin::API::VERSION}",
58
- 'X-Ruby-Version' => RUBY_VERSION,
59
- 'X-Ruby-Platform' => RUBY_PLATFORM
60
- }.merge(options[:headers])
61
-
62
- options[:params] = {
63
- :key => @api_key,
64
- :'account-key' => @account_key,
65
- :json => true
66
- }.merge(options[:params])
67
-
68
- RestClient.proxy = ENV['http_proxy'] if ENV['http_proxy']
69
- @connection = RestClient::Resource.new(@base_url, options)
70
- end
71
-
72
- def request(params, &block)
73
- # Returns a query hash with non nil values.
74
- params[:query].reject! { |_, value| value.nil? } if params[:query]
75
-
76
- case params[:method]
77
- when :post
78
- query = @connection.options.merge(params[:query] || {})
79
- @connection[params[:path]].post(query) { |response, _, _|
80
- @response = response
81
- }
82
- when :get
83
- query = @connection.options[:params].merge(params[:query] || {})
84
- @connection[params[:path]].get(:params => query) { |response, _, _|
85
- @response = response
86
- }
87
- end
88
-
89
- log.debug("args: #{@response.request.args}") if log
90
-
91
- if @response.headers[:content_disposition]
92
- filename = params[:output] || @response.headers[:content_disposition][/attachment; filename="(.+?)"/, 1]
93
- body = @response.body
94
- file = open(filename, 'wb')
95
- file.write(body)
96
- file.close
97
- return true
98
- else
99
- doc = JSON.load(@response.body)
100
- log.debug("body: #{doc}") if log
101
-
102
- if doc.kind_of?(Hash) && doc['success'] == false
103
- code = doc['error']['code']
104
- message = doc['error']['message']
105
- error = Crowdin::API::Errors::Error.new(code, message)
106
- raise(error)
107
- else
108
- return doc
109
- end
110
- end
111
-
112
- end
113
-
114
- # The current logger. If no logger has been set Crowdin::API.log is used.
115
- #
116
- def log
117
- @log || Crowdin::API.log
118
- end
119
-
120
- # Sets the +logger+ used by this instance of Crowdin::API
121
- #
122
- def log= logger
123
- @log = logger
124
- end
125
-
126
- private
127
7
 
128
- end
129
- end
8
+ # Core modules
9
+ require 'crowdin-api/core/errors'
10
+ require 'crowdin-api/core/api_errors_raiser'
11
+ require 'crowdin-api/core/request'
12
+
13
+ # Api modules
14
+ require 'crowdin-api/api-resources/languages'
15
+ require 'crowdin-api/api-resources/projects'
16
+ require 'crowdin-api/api-resources/source_files'
17
+ require 'crowdin-api/api-resources/storages'
18
+ require 'crowdin-api/api-resources/translation_status'
19
+ require 'crowdin-api/api-resources/translations'
20
+ require 'crowdin-api/api-resources/workflows'
21
+ require 'crowdin-api/api-resources/source_strings'
22
+
23
+ # Client
24
+ require 'crowdin-api/client/version'
25
+ require 'crowdin-api/client/configuration'
26
+ require 'crowdin-api/client/client'