ruby-lokalise-api 2.9.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODE_OF_CONDUCT.md +1 -1
  3. data/.github/CONTRIBUTING.md +9 -2
  4. data/CHANGELOG.md +1 -75
  5. data/LICENSE +9 -18
  6. data/README.md +18 -1734
  7. data/lib/ruby-lokalise-api.rb +2 -0
  8. data/lib/ruby-lokalise-api/client.rb +16 -4
  9. data/lib/ruby-lokalise-api/collections/base.rb +5 -3
  10. data/lib/ruby-lokalise-api/collections/queued_process.rb +15 -0
  11. data/lib/ruby-lokalise-api/connection.rb +1 -1
  12. data/lib/ruby-lokalise-api/data/attributes.json +29 -13
  13. data/lib/ruby-lokalise-api/request.rb +8 -1
  14. data/lib/ruby-lokalise-api/resources/base.rb +55 -25
  15. data/lib/ruby-lokalise-api/resources/branch.rb +1 -1
  16. data/lib/ruby-lokalise-api/resources/contributor.rb +1 -1
  17. data/lib/ruby-lokalise-api/resources/custom_translation_status.rb +1 -1
  18. data/lib/ruby-lokalise-api/resources/file.rb +3 -1
  19. data/lib/ruby-lokalise-api/resources/key.rb +1 -1
  20. data/lib/ruby-lokalise-api/resources/key_comment.rb +1 -1
  21. data/lib/ruby-lokalise-api/resources/order.rb +2 -0
  22. data/lib/ruby-lokalise-api/resources/payment_card.rb +1 -1
  23. data/lib/ruby-lokalise-api/resources/project.rb +2 -2
  24. data/lib/ruby-lokalise-api/resources/project_language.rb +1 -1
  25. data/lib/ruby-lokalise-api/resources/queued_process.rb +18 -0
  26. data/lib/ruby-lokalise-api/resources/screenshot.rb +1 -1
  27. data/lib/ruby-lokalise-api/resources/snapshot.rb +3 -1
  28. data/lib/ruby-lokalise-api/resources/task.rb +1 -1
  29. data/lib/ruby-lokalise-api/resources/team_user.rb +1 -1
  30. data/lib/ruby-lokalise-api/resources/team_user_group.rb +2 -1
  31. data/lib/ruby-lokalise-api/resources/translation.rb +1 -1
  32. data/lib/ruby-lokalise-api/resources/translation_provider.rb +3 -0
  33. data/lib/ruby-lokalise-api/resources/webhook.rb +11 -3
  34. data/lib/ruby-lokalise-api/rest/comments.rb +5 -5
  35. data/lib/ruby-lokalise-api/rest/contributors.rb +5 -5
  36. data/lib/ruby-lokalise-api/rest/custom_translation_statuses.rb +6 -6
  37. data/lib/ruby-lokalise-api/rest/files.rb +3 -3
  38. data/lib/ruby-lokalise-api/rest/keys.rb +7 -7
  39. data/lib/ruby-lokalise-api/rest/languages.rb +6 -6
  40. data/lib/ruby-lokalise-api/rest/payment_cards.rb +3 -3
  41. data/lib/ruby-lokalise-api/rest/projects.rb +6 -6
  42. data/lib/ruby-lokalise-api/rest/queued_processes.rb +26 -0
  43. data/lib/ruby-lokalise-api/rest/screenshots.rb +5 -5
  44. data/lib/ruby-lokalise-api/rest/snapshots.rb +4 -4
  45. data/lib/ruby-lokalise-api/rest/tasks.rb +5 -5
  46. data/lib/ruby-lokalise-api/rest/team_user_group.rb +4 -4
  47. data/lib/ruby-lokalise-api/rest/team_users.rb +4 -4
  48. data/lib/ruby-lokalise-api/rest/teams.rb +1 -1
  49. data/lib/ruby-lokalise-api/rest/translation_providers.rb +2 -2
  50. data/lib/ruby-lokalise-api/rest/translations.rb +3 -3
  51. data/lib/ruby-lokalise-api/rest/webhooks.rb +16 -5
  52. data/lib/ruby-lokalise-api/utils/attribute_helpers.rb +11 -6
  53. data/lib/ruby-lokalise-api/version.rb +1 -1
  54. data/ruby-lokalise-api.gemspec +7 -7
  55. data/spec/lib/ruby-lokalise-api/custom_json_parser_spec.rb +4 -4
  56. data/spec/lib/ruby-lokalise-api/error_spec.rb +8 -0
  57. data/spec/lib/ruby-lokalise-api/rest/branches_spec.rb +12 -0
  58. data/spec/lib/ruby-lokalise-api/rest/comments_spec.rb +12 -0
  59. data/spec/lib/ruby-lokalise-api/rest/contributors_spec.rb +12 -0
  60. data/spec/lib/ruby-lokalise-api/rest/custom_translation_statuses_spec.rb +12 -0
  61. data/spec/lib/ruby-lokalise-api/rest/files_spec.rb +17 -9
  62. data/spec/lib/ruby-lokalise-api/rest/keys_spec.rb +38 -20
  63. data/spec/lib/ruby-lokalise-api/rest/languages_spec.rb +12 -0
  64. data/spec/lib/ruby-lokalise-api/rest/orders_spec.rb +12 -0
  65. data/spec/lib/ruby-lokalise-api/rest/payment_cards_spec.rb +19 -5
  66. data/spec/lib/ruby-lokalise-api/rest/projects_spec.rb +12 -0
  67. data/spec/lib/ruby-lokalise-api/rest/queued_processes_spec.rb +57 -0
  68. data/spec/lib/ruby-lokalise-api/rest/screenshots_spec.rb +12 -0
  69. data/spec/lib/ruby-lokalise-api/rest/snapshots_spec.rb +25 -0
  70. data/spec/lib/ruby-lokalise-api/rest/tasks_spec.rb +20 -7
  71. data/spec/lib/ruby-lokalise-api/rest/team_user_groups_spec.rb +84 -0
  72. data/spec/lib/ruby-lokalise-api/rest/team_users_spec.rb +13 -0
  73. data/spec/lib/ruby-lokalise-api/rest/translation_providers_spec.rb +5 -0
  74. data/spec/lib/ruby-lokalise-api/rest/translations_spec.rb +12 -0
  75. data/spec/lib/ruby-lokalise-api/rest/webhooks_spec.rb +50 -0
  76. metadata +25 -20
@@ -17,6 +17,7 @@ require 'ruby-lokalise-api/resources/base'
17
17
  require 'ruby-lokalise-api/resources/branch'
18
18
  require 'ruby-lokalise-api/resources/project'
19
19
  require 'ruby-lokalise-api/resources/project_language'
20
+ require 'ruby-lokalise-api/resources/queued_process'
20
21
  require 'ruby-lokalise-api/resources/key_comment'
21
22
  require 'ruby-lokalise-api/resources/contributor'
22
23
  require 'ruby-lokalise-api/resources/file'
@@ -43,6 +44,7 @@ require 'ruby-lokalise-api/collections/team'
43
44
  require 'ruby-lokalise-api/collections/system_language'
44
45
  require 'ruby-lokalise-api/collections/project_language'
45
46
  require 'ruby-lokalise-api/collections/project_comment'
47
+ require 'ruby-lokalise-api/collections/queued_process'
46
48
  require 'ruby-lokalise-api/collections/key_comment'
47
49
  require 'ruby-lokalise-api/collections/key'
48
50
  require 'ruby-lokalise-api/collections/contributor'
@@ -4,6 +4,7 @@ require 'ruby-lokalise-api/rest/branches'
4
4
  require 'ruby-lokalise-api/rest/languages'
5
5
  require 'ruby-lokalise-api/rest/teams'
6
6
  require 'ruby-lokalise-api/rest/projects'
7
+ require 'ruby-lokalise-api/rest/queued_processes'
7
8
  require 'ruby-lokalise-api/rest/comments'
8
9
  require 'ruby-lokalise-api/rest/keys'
9
10
  require 'ruby-lokalise-api/rest/contributors'
@@ -27,14 +28,25 @@ module Lokalise
27
28
 
28
29
  def initialize(token, params = {})
29
30
  @token = token
30
- @timeout = params.fetch(:timeout) { nil }
31
- @open_timeout = params.fetch(:open_timeout) { nil }
31
+ @timeout = params.fetch(:timeout, nil)
32
+ @open_timeout = params.fetch(:open_timeout, nil)
32
33
  end
33
34
 
34
- def construct_request(klass, method, endpoint_ids, params = {}, object_key = nil)
35
+ # rubocop:disable Metrics/ParameterLists
36
+ # Constructs request to perform the specified action
37
+ # @param klass The actual class to call the method upon
38
+ # @param method [Symbol] The method to call (:new, :update, :create etc)
39
+ # @param endpoint_ids [Array, Hash] IDs that are used to generate the proper path to the endpoint
40
+ # @param params [Array, Hash] Request parameters
41
+ # @param object_key [String, Symbol] Key that should be used to wrap parameters into
42
+ # @param initial_ids [Array] IDs that should be used to generate base endpoint path. The base path is used for method chaining
43
+ def construct_request(klass, method, endpoint_ids, params = {}, object_key = nil, initial_ids = nil)
35
44
  path = klass.endpoint(*endpoint_ids)
36
- klass.send method, self, path, format_params(params, object_key)
45
+ formatted_params = format_params(params, object_key)
46
+ formatted_params[:_initial_path] = klass.endpoint(*initial_ids) if initial_ids
47
+ klass.send method, self, path, formatted_params
37
48
  end
49
+ # rubocop:enable Metrics/ParameterLists
38
50
 
39
51
  # Converts `params` to hash with arrays under the `object_key` key.
40
52
  # Used in bulk operations
@@ -9,7 +9,7 @@ module Lokalise
9
9
  extend Lokalise::Utils::EndpointHelpers
10
10
 
11
11
  attr_reader :total_pages, :total_results, :results_per_page, :current_page, :collection,
12
- :project_id, :team_id, :request_params, :client, :path
12
+ :project_id, :team_id, :request_params, :client, :path, :branch, :user_id
13
13
 
14
14
  # Initializes a new collection based on the response
15
15
  #
@@ -19,9 +19,11 @@ module Lokalise
19
19
  def initialize(response, params = {})
20
20
  produce_collection_for response
21
21
  populate_pagination_data_for response
22
- # Project and team id may not be present in some cases
22
+ # Project, team id, user id, and branch may not be present in some cases
23
23
  @project_id = response['content']['project_id']
24
24
  @team_id = response['content']['team_id']
25
+ @user_id = response['content']['user_id']
26
+ @branch = response['content']['branch']
25
27
  @request_params = params
26
28
  @client = response['client']
27
29
  @path = response['path']
@@ -89,7 +91,7 @@ module Lokalise
89
91
  # Collection example: `{ "content": {"comments": [ ... ]} }`
90
92
  def produce_collection_for(response)
91
93
  model_class = self.class.name.base_class_name
92
- data_key_plural = data_key_for model_class, true, true
94
+ data_key_plural = data_key_for model_class: model_class, plural: true, collection: true
93
95
 
94
96
  # Fetch collection data and instantiate an individual resource for each object
95
97
  # We also preserve the `client` to be able to chain API methods later
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lokalise
4
+ module Collections
5
+ class QueuedProcess < Base
6
+ DATA_KEY_PLURAL = 'Processes'
7
+
8
+ class << self
9
+ def endpoint(project_id, *_args)
10
+ path_from projects: [project_id, 'processes']
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Lokalise
4
4
  module Connection
5
- BASE_URL = 'https://api.lokalise.co/api2/'
5
+ BASE_URL = 'https://api.lokalise.com/api2/'
6
6
 
7
7
  def connection(client)
8
8
  options = {
@@ -21,11 +21,11 @@
21
21
  "email",
22
22
  "fullname",
23
23
  "created_at",
24
+ "created_at_timestamp",
24
25
  "is_admin",
25
26
  "is_reviewer",
26
27
  "languages",
27
- "admin_rights",
28
- "created_at_timestamp"
28
+ "admin_rights"
29
29
  ],
30
30
  "custom_translation_status": [
31
31
  "status_id",
@@ -39,6 +39,7 @@
39
39
  "key": [
40
40
  "key_id",
41
41
  "created_at",
42
+ "created_at_timestamp",
42
43
  "key_name",
43
44
  "filenames",
44
45
  "description",
@@ -55,7 +56,10 @@
55
56
  "base_words",
56
57
  "char_limit",
57
58
  "custom_attributes",
58
- "created_at_timestamp"
59
+ "modified_at",
60
+ "modified_at_timestamp",
61
+ "translations_modified_at",
62
+ "translations_modified_at_timestamp"
59
63
  ],
60
64
  "language": [
61
65
  "lang_id",
@@ -70,6 +74,7 @@
70
74
  "card_id",
71
75
  "status",
72
76
  "created_at",
77
+ "created_at_timestamp",
73
78
  "created_by",
74
79
  "created_by_email",
75
80
  "source_language_iso",
@@ -81,8 +86,7 @@
81
86
  "translation_tier",
82
87
  "translation_tier_name",
83
88
  "briefing",
84
- "total",
85
- "created_at_timestamp"
89
+ "total"
86
90
  ],
87
91
  "payment_card": [
88
92
  "card_id",
@@ -96,15 +100,26 @@
96
100
  "name",
97
101
  "description",
98
102
  "created_at",
103
+ "created_at_timestamp",
99
104
  "created_by",
100
105
  "created_by_email",
101
106
  "team_id",
102
- "created_at_timestamp",
103
107
  "base_language_id",
104
108
  "base_language_iso",
105
109
  "settings",
106
110
  "statistics"
107
111
  ],
112
+ "queued_process": [
113
+ "process_id",
114
+ "type",
115
+ "status",
116
+ "message",
117
+ "created_by",
118
+ "created_by_email",
119
+ "created_at",
120
+ "created_at_timestamp",
121
+ "details"
122
+ ],
108
123
  "screenshot": [
109
124
  "screenshot_id",
110
125
  "key_ids",
@@ -121,9 +136,9 @@
121
136
  "snapshot_id",
122
137
  "title",
123
138
  "created_at",
139
+ "created_at_timestamp",
124
140
  "created_by",
125
- "created_by_email",
126
- "created_at_timestamp"
141
+ "created_by_email"
127
142
  ],
128
143
  "task": [
129
144
  "task_id",
@@ -147,6 +162,7 @@
147
162
  "languages",
148
163
  "auto_close_languages",
149
164
  "auto_close_task",
165
+ "auto_close_items",
150
166
  "completed_at",
151
167
  "completed_at_timestamp",
152
168
  "completed_by",
@@ -157,18 +173,18 @@
157
173
  "team_id",
158
174
  "name",
159
175
  "created_at",
176
+ "created_at_timestamp",
160
177
  "plan",
161
178
  "quota_usage",
162
- "quota_allowed",
163
- "created_at_timestamp"
179
+ "quota_allowed"
164
180
  ],
165
181
  "team_user": [
166
182
  "user_id",
167
183
  "email",
168
184
  "fullname",
169
185
  "created_at",
170
- "role",
171
- "created_at_timestamp"
186
+ "created_at_timestamp",
187
+ "role"
172
188
  ],
173
189
  "team_user_group": [
174
190
  "group_id",
@@ -211,4 +227,4 @@
211
227
  "events",
212
228
  "event_lang_map"
213
229
  ]
214
- }
230
+ }
@@ -29,6 +29,13 @@ module Lokalise
29
29
  )
30
30
  end
31
31
 
32
+ def patch(path, client, params = {})
33
+ respond_with(
34
+ connection(client).patch(prepare(path), params.any? ? custom_dump(params) : nil),
35
+ client
36
+ )
37
+ end
38
+
32
39
  def delete(path, client, params = {})
33
40
  respond_with(
34
41
  # Rubocop tries to replace `delete` with `gsub` but that's a different method here!
@@ -45,7 +52,7 @@ module Lokalise
45
52
 
46
53
  # Get rid of double slashes in the `path`, leading and trailing slash
47
54
  def prepare(path)
48
- path.gsub(%r{\A/}, '').gsub(%r{//}, '/').gsub(%r{/+\z}, '')
55
+ path.delete_prefix('/').gsub(%r{//}, '/').gsub(%r{/+\z}, '')
49
56
  end
50
57
 
51
58
  def respond_with(response, client)
@@ -8,25 +8,27 @@ module Lokalise
8
8
  include Lokalise::Utils::AttributeHelpers
9
9
  extend Lokalise::Utils::EndpointHelpers
10
10
 
11
- attr_reader :raw_data, :project_id, :client, :path
11
+ attr_reader :raw_data, :project_id, :client, :path, :branch, :user_id, :team_id
12
12
 
13
- # Initializes a new resource based on the response
13
+ # Initializes a new resource based on the response.
14
+ # `endpoint_generator` is used in cases when a new instance is generated
15
+ # from a different resource. For example, restoring from a snapshot
16
+ # creates a totally different project which should have a new path.
14
17
  #
15
18
  # @param response [Hash]
19
+ # @param endpoint_generator [Proc] Generate proper paths for certain resources
16
20
  # @return [Lokalise::Resources::Base]
17
- def initialize(response)
21
+ def initialize(response, endpoint_generator = nil)
18
22
  populate_attributes_for response['content']
19
-
20
- @raw_data = response['content']
21
- @project_id = response['content']['project_id']
23
+ extract_common_attributes_for response['content']
22
24
  @client = response['client']
23
- @path = infer_path_from response
25
+ @path = infer_path_from response, endpoint_generator
24
26
  end
25
27
 
26
28
  class << self
27
- # Dynamically add attribute readers for each inherited class.
29
+ # Dynamically adds attribute readers for each inherited class.
28
30
  # Attributes are defined in the `data/attributes.json` file.
29
- # Also set the `ATTRIBUTES` constant to assign values to each attribute later when
31
+ # Also sets the `ATTRIBUTES` constant to assign values to each attribute later when
30
32
  # the response arrives from the API
31
33
  def inherited(subclass)
32
34
  klass_attributes = attributes_for subclass
@@ -43,10 +45,16 @@ module Lokalise
43
45
  # Usage: `supports :update, :destroy, [:complex_method, '/sub/path', :update]`
44
46
  def supports(*methods)
45
47
  methods.each do |m_data|
46
- method_name, sub_path, c_method = m_data.is_a?(Array) ? m_data : [m_data, '', m_data]
48
+ # `method_name` - the method that the resource should support
49
+ # `sub_path` - a string that has to be appended to a base path
50
+ # `c_method` - method name to delegate the work to
51
+ method_name, sub_path, c_method =
52
+ m_data.is_a?(Array) ? m_data : [m_data, '', m_data]
53
+
47
54
  define_method method_name do |params = {}|
48
55
  path = instance_variable_get(:@path)
49
- # If there's a sub_path, preserve the initial path to allow further chaining
56
+ # If there's a sub_path which is a string,
57
+ # preserve the initial path to allow further chaining
50
58
  params = params.merge(_initial_path: path) if sub_path
51
59
  self.class.send c_method, instance_variable_get(:@client),
52
60
  path + sub_path, params
@@ -56,34 +64,38 @@ module Lokalise
56
64
 
57
65
  # Fetches a single record
58
66
  def find(client, path, params = {})
59
- new get(path, client, params)
67
+ new get(path, client, prepare_params(params))
60
68
  end
61
69
 
62
70
  # Creates one or multiple records
63
71
  def create(client, path, params)
64
- response = post path, client, params
65
-
72
+ response = post path, client, prepare_params(params)
66
73
  object_from response, params
67
74
  end
68
75
 
69
76
  # Updates one or multiple records
70
77
  def update(client, path, params)
71
- response = put path, client, params
72
-
78
+ response = put path, client, prepare_params(params)
73
79
  object_from response, params
74
80
  end
75
81
 
76
82
  # Destroys records by given ids
77
83
  def destroy(client, path, params = {})
78
- delete(path, client, params)['content']
84
+ delete(path, client, prepare_params(params))['content']
79
85
  end
80
86
 
81
87
  private
82
88
 
89
+ # Filters out internal attributes that should not be sent to Lokalise
90
+ def prepare_params(params)
91
+ filter_attrs = %i[_initial_path]
92
+ params.reject { |key, _v| filter_attrs.include?(key) }
93
+ end
94
+
83
95
  # Instantiates a new resource or collection based on the given response
84
96
  def object_from(response, params)
85
97
  model_class = name.base_class_name
86
- data_key_plural = data_key_for model_class, true
98
+ data_key_plural = data_key_for model_class: model_class, plural: true
87
99
  # Preserve the initial path to allow chaining
88
100
  response['path'] = params.delete(:_initial_path) if params.key?(:_initial_path)
89
101
 
@@ -95,8 +107,7 @@ module Lokalise
95
107
  end
96
108
 
97
109
  def produce_resource(model_class, response)
98
- data_key_singular = data_key_for model_class
99
-
110
+ data_key_singular = data_key_for model_class: model_class
100
111
  if response['content'].key? data_key_singular
101
112
  data = response['content'].delete data_key_singular
102
113
  response['content'].merge! data
@@ -111,20 +122,27 @@ module Lokalise
111
122
  end
112
123
 
113
124
  # Generates path for the individual resource based on the path for the collection
114
- def infer_path_from(response)
125
+ def infer_path_from(response, endpoint_generator = nil)
115
126
  id_key = id_key_for self.class.name.base_class_name
116
- data_key = data_key_for self.class.name.base_class_name
127
+ data_key = data_key_for model_class: self.class.name.base_class_name
117
128
 
118
- path_with_id response, id_key, data_key
129
+ path_with_id response, id_key, data_key, endpoint_generator
119
130
  end
120
131
 
121
- def path_with_id(response, id_key, data_key)
132
+ def path_with_id(response, id_key, data_key, endpoint_generator = nil)
122
133
  # Some resources do not have ids at all
123
134
  return nil unless response['content'].key?(id_key) || response['content'].key?(data_key)
124
135
 
125
136
  # ID of the resource
126
137
  id = id_from response, id_key, data_key
127
138
 
139
+ # If `endpoint_generator` is present, generate a new path
140
+ # based on the fetched id
141
+ if endpoint_generator
142
+ path = endpoint_generator.call project_id, id
143
+ return path.remove_trailing_slash
144
+ end
145
+
128
146
  path = response['path'] || response['base_path']
129
147
  # If path already has id - just return it
130
148
  return path if path.match?(/#{id}\z/)
@@ -146,7 +164,7 @@ module Lokalise
146
164
  # Store all resources attributes under the corresponding instance variables.
147
165
  # `ATTRIBUTES` is defined inside resource-specific classes
148
166
  def populate_attributes_for(content)
149
- data_key = data_key_for self.class.name.base_class_name
167
+ data_key = data_key_for model_class: self.class.name.base_class_name
150
168
 
151
169
  self.class.const_get(:ATTRIBUTES).each do |attr|
152
170
  value = if content.key?(data_key) && content[data_key].is_a?(Hash)
@@ -158,6 +176,18 @@ module Lokalise
158
176
  instance_variable_set "@#{attr}", value
159
177
  end
160
178
  end
179
+
180
+ # Extracts all common attributes that resources have.
181
+ # Some of them may be absent in certain cases.
182
+ # rubocop:disable Naming/MemoizedInstanceVariableName
183
+ def extract_common_attributes_for(content)
184
+ @raw_data = content
185
+ @project_id ||= content['project_id']
186
+ @user_id ||= content['user_id']
187
+ @team_id ||= content['team_id']
188
+ @branch ||= content['branch']
189
+ end
190
+ # rubocop:enable Naming/MemoizedInstanceVariableName
161
191
  end
162
192
  end
163
193
  end
@@ -3,7 +3,7 @@
3
3
  module Lokalise
4
4
  module Resources
5
5
  class Branch < Base
6
- supports :update, :destroy
6
+ supports :update, :destroy, [:reload_data, '', :find]
7
7
 
8
8
  def merge(params = {})
9
9
  self.class.merge @client, self.class.endpoint(project_id, branch_id, :merge), params
@@ -4,7 +4,7 @@ module Lokalise
4
4
  module Resources
5
5
  class Contributor < Base
6
6
  ID_KEY = 'user'
7
- supports :update, :destroy
7
+ supports :update, :destroy, [:reload_data, '', :find]
8
8
 
9
9
  class << self
10
10
  def endpoint(project_id, contributor_id = nil)