# frozen_string_literal: true # # A wrapper and interface to the Crowdin API. Please visit the Crowdin developers site # for a full explanation of what each of the Crowdin api methods expect and perform. # # https://support.crowdin.com/api/v2/ # https://support.crowdin.com/enterprise/api/ # module Crowdin # # === Example # # require 'crowdin-api' # # crowdin = Crowdin::Client.new do |config| # config.api_token = 'YOUR_API_TOKEN' # end # # crowdin.list_projects # class Client # Processing API Resources modules to include them to the Client API_RESOURCES_MODULES.each do |module_name| Client.send(:include, Object.const_get("Crowdin::ApiResources::#{module_name}")) end # Processing Error Raisers modules to include them to the Client ERROR_RAISERS_MODULES.each do |module_name| Client.send(:include, Object.const_get("Crowdin::Errors::#{module_name}")) end include Web::FetchAllExtensions # Config instance that includes configuration options for the Client attr_reader :config # Instance with established connection through RestClient to the Crowdin API attr_reader :connection # Instance with options and headers for RestClient connection attr_reader :options # Logger instance attr_reader :logger def initialize(&block) build_configuration(&block) update_logger update_rest_client_proxy build_connection end def log(message) !logger_enabled? || logger.debug(message) end def logger=(logger) raise_logger_are_not_enabled_error unless logger_enabled? @logger = logger update_rest_client_logger end def enterprise_mode? !!config.organization_domain end def logger_enabled? config.logger_enabled? end # # FetchAll options: # * limit, Integer, default: 500 | How many records need to load per one request # * offset, Integer, default: 0 | How many records need to skip # * request_delay, Integer (seconds), default: 0 | Delay between requests # # # Note: Please, specify project_id while Client initialization if you need to use methods that need it within FetchAll # # === Example # # @crowdin.fetch_all(:list_projects) # # with specified options # # @crowdin.fetch_all(:list_projects, { limit: 10, request_delay: 1 }) # # playing with response per fetch. Note: the block actually don't make any effect to finite result # # @crowdin.fetch_all(:list_projects, { limit: 10, request_delay: 1 }) { |response| puts response['data'] } # # also you can specify retry configuration to handle some exceptions # # Retry configuration options: # * request_delay, Integer (seconds), default: 0 | Delay between retries # * retries_count, Integer, default: 0 # * error_messages, Array # # @crowdin.fetch_all(:list_projects, {}, { request_delay: 2, retries_count: 3, error_messages: ['401'] }) # # fetch all execution will be terminated if response error are same as in error_messages array # otherwise system will retry so many times, as indicated at tries_count # def fetch_all(api_resource, opts = {}, retry_opts = {}) unless api_resource.to_s.start_with?('list_') raise(Errors::FetchAllProcessingError, "#{api_resource} method aren't supported for FetchAll") end limit = opts[:limit] || Web::FetchAllExtensions::MAX_ITEMS_COUNT_PER_REQUEST offset = opts[:offset] || 0 request_delay = opts[:request_delay] || 0 retry_request_delay = retry_opts[:request_delay] || 0 retries_count = retry_opts[:retries_count] || 0 retry_error_messages = retry_opts[:error_messages] || [] result = [] loop do response = case api_resource when :list_terms send(api_resource, opts[:glossary_id], { limit: limit, offset: offset }.merge(opts)) when :list_file_revisions send(api_resource, opts[:file_id], { limit: limit, offset: offset }.merge(opts)) else send(api_resource, { limit: limit, offset: offset }.merge(opts)) end if response.is_a?(String) && response.match('Something went wrong') if retries_count.positive? retry_error_messages.each do |message| break if response.match(message) end retries_count -= 1 sleep retry_request_delay else raise(Errors::FetchAllProcessingError, response) end else yield response if block_given? deserialized_response = response['data'] result.concat(deserialized_response) offset += deserialized_response.size break if deserialized_response.size < limit end sleep request_delay end result rescue StandardError => e raise(Errors::FetchAllProcessingError, "FetchAll wasn't processed. Details - #{e.message}") end private def build_configuration @config = Crowdin::Configuration.new yield config if block_given? end def build_connection build_options @connection ||= ::RestClient::Resource.new(config.base_url, options) end def build_options @options ||= config.options.merge(headers: config.headers) end def set_default_logger require 'logger' @logger ||= Logger.new($stdout) update_rest_client_logger end def update_rest_client_logger ::RestClient.log = @logger end def update_rest_client_proxy ENV['http_proxy'] ? ::RestClient.proxy = ENV.fetch('http_proxy') : false end def update_logger config.logger_enabled? ? set_default_logger : config.enable_logger = false end end end