contentful-management 1.6.0 → 1.7.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/.rubocop_todo.yml +3 -3
  4. data/.travis.yml +4 -3
  5. data/CHANGELOG.md +5 -0
  6. data/Gemfile +0 -8
  7. data/Guardfile +3 -54
  8. data/README.md +45 -0
  9. data/Rakefile +0 -5
  10. data/contentful-management.gemspec +8 -5
  11. data/lib/contentful/management/client.rb +44 -14
  12. data/lib/contentful/management/client_upload_methods_factory.rb +19 -0
  13. data/lib/contentful/management/content_type.rb +19 -19
  14. data/lib/contentful/management/dynamic_entry.rb +1 -1
  15. data/lib/contentful/management/entry.rb +57 -50
  16. data/lib/contentful/management/http_client.rb +7 -1
  17. data/lib/contentful/management/request.rb +14 -9
  18. data/lib/contentful/management/resource.rb +7 -7
  19. data/lib/contentful/management/resource/array_like.rb +2 -2
  20. data/lib/contentful/management/resource/system_properties.rb +2 -1
  21. data/lib/contentful/management/resource_builder.rb +6 -3
  22. data/lib/contentful/management/resource_requester.rb +3 -3
  23. data/lib/contentful/management/support.rb +1 -1
  24. data/lib/contentful/management/upload.rb +42 -0
  25. data/lib/contentful/management/version.rb +1 -1
  26. data/spec/fixtures/pixel.jpg +0 -0
  27. data/spec/fixtures/vcr_cassettes/upload/associate_with_asset.yml +426 -0
  28. data/spec/fixtures/vcr_cassettes/upload/create_file.yml +85 -0
  29. data/spec/fixtures/vcr_cassettes/upload/create_path.yml +85 -0
  30. data/spec/fixtures/vcr_cassettes/upload/destroy.yml +133 -0
  31. data/spec/fixtures/vcr_cassettes/upload/find.yml +82 -0
  32. data/spec/fixtures/vcr_cassettes/upload/find_not_found.yml +66 -0
  33. data/spec/lib/contentful/management/client_spec.rb +25 -0
  34. data/spec/lib/contentful/management/upload_spec.rb +92 -0
  35. data/spec/spec_helper.rb +9 -1
  36. metadata +91 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 59a0b72970e30e8e4fa850361c2ed6c52603e6b0
4
- data.tar.gz: b1f2d446a426a052a8ca164e1f9ca3a9b15f8212
3
+ metadata.gz: c880b5d6e4f5f9b5cf11599a5177de92c8cfb673
4
+ data.tar.gz: 57ed6666b81a6767b4c7d5b1b315d2bf64f3e7e2
5
5
  SHA512:
6
- metadata.gz: d245df3cd7ab483f306fd8fb7823cfbe41bb3b93c4fa1798c8833ac6fcfdbbba4eb62b72c0ef5be78bcc963528ac0983436594c79005309262d83340eca1a199
7
- data.tar.gz: 03b149bc58082a045ccda45820f07c590616a50c96ce3af8777ada574f6ab7f453b57f8197b754f687ea60f679f7c162020f5973b064ad783b47fa157ca42a3b
6
+ metadata.gz: e590866845d60f709bfd6b525f2a7a4ef779373e78e57881e375237f52ea54e3b66a52d221052cab7a572c3a609127cfbb8aa41a0cd3cddaca9a01e447dce278
7
+ data.tar.gz: f115b17339749173bdbd4c883b8d3cc0d99ceaa398f3b30639959a31ebcfc5751d01a9b61198deae79f5fd019d2c91b883836a2f06f95f8895ec1c4bc2c437af
data/.rubocop.yml CHANGED
@@ -21,3 +21,6 @@ Metrics/LineLength:
21
21
 
22
22
  Metrics/ClassLength:
23
23
  Max: 250
24
+
25
+ Style/SignalException:
26
+ EnforcedStyle: 'semantic'
data/.rubocop_todo.yml CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  # Offense count: 12
10
10
  Metrics/AbcSize:
11
- Max: 41
11
+ Max: 45
12
12
 
13
13
  # Offense count: 4
14
14
  Metrics/CyclomaticComplexity:
@@ -17,8 +17,8 @@ Metrics/CyclomaticComplexity:
17
17
  # Offense count: 18
18
18
  # Configuration parameters: CountComments.
19
19
  Metrics/MethodLength:
20
- Max: 24
20
+ Max: 25
21
21
 
22
22
  # Offense count: 2
23
23
  Metrics/PerceivedComplexity:
24
- Max: 9
24
+ Max: 10
data/.travis.yml CHANGED
@@ -1,13 +1,14 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.2.3
4
+ - 2.3.1
5
+ - 2.4.0
4
6
  - 2.1.1
5
7
  - 2.1
6
8
  - 2.0.0
7
- - 1.9.3
8
- - jruby-19mode
9
+ - jruby-head
9
10
 
10
- before_install: gem install bundler -v 1.10.6
11
+ before_install: gem install bundler
11
12
  script: bundle exec rake rspec_rubocop
12
13
  notifications:
13
14
  slack:
data/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## Master
4
4
 
5
+ ## 1.7.0
6
+
7
+ ### Added
8
+ * Added support for Upload API
9
+
5
10
  ## 1.6.0
6
11
 
7
12
  ### Added
data/Gemfile CHANGED
@@ -4,13 +4,5 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :development do
7
- gem 'guard'
8
- gem 'listen', '3.0.0'
9
- gem 'guard-rspec'
10
- gem 'guard-rubocop'
11
7
  gem 'pry'
12
8
  end
13
-
14
- group :test do
15
- gem 'simplecov', require: false
16
- end
data/Guardfile CHANGED
@@ -1,29 +1,3 @@
1
- # A sample Guardfile
2
- # More info at https://github.com/guard/guard#readme
3
-
4
- ## Uncomment and set this to only include directories you want to watch
5
- # directories %w(app lib config test spec features) \
6
- # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
7
-
8
- ## Note: if you are using the `directories` clause above and you are not
9
- ## watching the project directory ('.'), then you will want to move
10
- ## the Guardfile to a watched dir and symlink it back, e.g.
11
- #
12
- # $ mkdir config
13
- # $ mv Guardfile config/
14
- # $ ln -s config/Guardfile .
15
- #
16
- # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17
-
18
- # Note: The cmd option is now required due to the increasing number of ways
19
- # rspec may be run, below are examples of the most common uses.
20
- # * bundler: 'bundle exec rspec'
21
- # * bundler binstubs: 'bin/rspec'
22
- # * spring: 'bin/rspec' (This will use spring if running and you have
23
- # installed the spring binstubs per the docs)
24
- # * zeus: 'zeus rspec' (requires the server to be started separately)
25
- # * 'just' rspec: 'rspec'
26
-
27
1
  group :green_red_refactor, halt_on_fail: true do
28
2
  guard :rspec, cmd: "bundle exec rspec --format documentation" do
29
3
  require "guard/rspec/dsl"
@@ -40,36 +14,11 @@ group :green_red_refactor, halt_on_fail: true do
40
14
  # Ruby files
41
15
  ruby = dsl.ruby
42
16
  dsl.watch_spec_files_for(ruby.lib_files)
43
-
44
- # Rails files
45
- rails = dsl.rails(view_extensions: %w(erb haml slim))
46
- dsl.watch_spec_files_for(rails.app_files)
47
- dsl.watch_spec_files_for(rails.views)
48
-
49
- watch(rails.controllers) do |m|
50
- [
51
- rspec.spec.("routing/#{m[1]}_routing"),
52
- rspec.spec.("controllers/#{m[1]}_controller"),
53
- rspec.spec.("acceptance/#{m[1]}")
54
- ]
55
- end
56
-
57
- # Rails config changes
58
- watch(rails.spec_helper) { rspec.spec_dir }
59
- watch(rails.routes) { "#{rspec.spec_dir}/routing" }
60
- watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
61
-
62
- # Capybara features specs
63
- watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
64
- watch(rails.layouts) { |m| rspec.spec.("features/#{m[1]}") }
65
-
66
- # Turnip features and steps
67
- watch(%r{^spec/acceptance/(.+)\.feature$})
68
- watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
69
- Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
70
- end
71
17
  end
72
18
 
73
19
  guard :rubocop, cmd: "rubocop" do
74
20
  end
21
+
22
+ guard :yard, cmd: "yard doc" do
23
+ end
75
24
  end
data/README.md CHANGED
@@ -196,6 +196,51 @@ Checking if an asset is published:
196
196
  my_image_asset.published?
197
197
  ```
198
198
 
199
+ ### File Uploads
200
+
201
+ Creating an upload from a file path:
202
+
203
+ ```ruby
204
+ upload = client.uploads.create('space_id', '/path/to/file.md')
205
+ ```
206
+
207
+ Alternatively, create it from an `::IO` object:
208
+
209
+ ```ruby
210
+ File.open('/path/to/file.md', 'rb') do |file|
211
+ upload = client.uploads.create('space_id', file)
212
+ end
213
+ ```
214
+
215
+ Finding an upload:
216
+
217
+ ```ruby
218
+ upload = client.uploads.find('space_id', 'upload_id')
219
+ ```
220
+
221
+ Deleting an upload
222
+
223
+ ```ruby
224
+ upload.destroy
225
+ ```
226
+
227
+ Associating an upload with an asset:
228
+
229
+ ```ruby
230
+ # We find or create an upload:
231
+ upload = client.uploads.find('space_id', 'upload_id')
232
+
233
+ # We create a File object with the associated upload:
234
+ file = Contentful::Management::File.new
235
+ file.properties[:contentType] = 'text/plain'
236
+ file.properties[:fileName] = 'file.md'
237
+ file.properties[:uploadFrom] = upload.to_link_json # We create the Link from the upload.
238
+
239
+ # We create an asset with the associated file:
240
+ asset = client.assets.create('space_id', title: 'My Upload', file: file)
241
+ asset.process_file # We process the file, to generate an URL for our upload.
242
+ ```
243
+
199
244
  ### Entries
200
245
 
201
246
  Retrieving all entries from the space:
data/Rakefile CHANGED
@@ -24,11 +24,6 @@ RSpec::Core::RakeTask.new
24
24
  require 'rubocop/rake_task'
25
25
  RuboCop::RakeTask.new
26
26
 
27
- require 'reek/rake/task'
28
- Reek::Rake::Task.new do |t|
29
- t.fail_on_error = false
30
- end
31
-
32
27
  desc 'Run specs, rubocop and reek'
33
28
  task ci: %w(spec reek rubocop)
34
29
 
@@ -17,19 +17,22 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ['lib']
19
19
 
20
- spec.add_dependency 'http', '~> 1.0'
20
+ spec.add_dependency 'http', '> 1.0', '< 3.0'
21
21
  spec.add_dependency 'multi_json', '~> 1'
22
22
  spec.add_dependency 'json', '~> 1.8'
23
23
 
24
24
  spec.add_development_dependency 'bundler', '~> 1.6'
25
25
  spec.add_development_dependency 'rake', '< 11.0'
26
26
  spec.add_development_dependency 'public_suffix', '< 1.5'
27
-
28
27
  spec.add_development_dependency 'rspec', '~> 3'
29
28
  spec.add_development_dependency 'rspec-its'
30
- spec.add_development_dependency 'rubocop'
31
- spec.add_development_dependency 'reek', '~> 2.2.1'
32
- spec.add_development_dependency 'unparser', '0.2.4'
29
+ spec.add_development_dependency 'guard'
30
+ spec.add_development_dependency 'guard-rspec'
31
+ spec.add_development_dependency 'guard-rubocop'
32
+ spec.add_development_dependency 'guard-yard'
33
+ spec.add_development_dependency 'rubocop', '~> 0.41.0'
34
+ spec.add_development_dependency 'listen', '3.0.0'
33
35
  spec.add_development_dependency 'vcr'
34
36
  spec.add_development_dependency 'webmock', '~> 1', '>= 1.17.3'
37
+ spec.add_development_dependency 'simplecov'
35
38
  end
@@ -14,6 +14,7 @@ require 'contentful/management/client_locale_methods_factory'
14
14
  require 'contentful/management/client_role_methods_factory'
15
15
  require 'contentful/management/client_editor_interface_methods_factory'
16
16
  require 'contentful/management/client_webhook_methods_factory'
17
+ require 'contentful/management/client_upload_methods_factory'
17
18
  require 'contentful/management/client_snapshot_methods_factory'
18
19
 
19
20
  require_relative 'request'
@@ -34,6 +35,7 @@ module Contentful
34
35
  # Default configuration for Contentful::Management::Client
35
36
  DEFAULT_CONFIGURATION = {
36
37
  api_url: 'api.contentful.com',
38
+ uploads_url: 'upload.contentful.com',
37
39
  api_version: '1',
38
40
  secure: true,
39
41
  default_locale: 'en-US',
@@ -48,9 +50,10 @@ module Contentful
48
50
  proxy_password: nil,
49
51
  max_rate_limit_retries: 1,
50
52
  max_rate_limit_wait: 60
51
- }
53
+ }.freeze
54
+
52
55
  # Rate Limit Reset Header Key
53
- RATE_LIMIT_RESET_HEADER_KEY = 'x-contentful-ratelimit-reset'
56
+ RATE_LIMIT_RESET_HEADER_KEY = 'x-contentful-ratelimit-reset'.freeze
54
57
 
55
58
  # @param [String] access_token
56
59
  # @param [Hash] configuration
@@ -156,6 +159,15 @@ module Contentful
156
159
  ClientWebhookMethodsFactory.new(self)
157
160
  end
158
161
 
162
+ # Allows manipulation of uploads in context of the current client
163
+ # Allows creating new and finding uploads by id.
164
+ # @see _ README for details.
165
+ #
166
+ # @return [Contentful::Management::ClientUploadMethodsFactory]
167
+ def uploads
168
+ ClientUploadMethodsFactory.new(self)
169
+ end
170
+
159
171
  # Allows manipulation of snapshots in context of the current client
160
172
  # Allows listing all webhooks for client, creating new and finding one by id.
161
173
  # @see _ README for details.
@@ -223,11 +235,11 @@ module Contentful
223
235
  # @private
224
236
  def execute_request(request)
225
237
  retries_left = configuration[:max_rate_limit_retries]
226
- request_url = request.url
227
- url = request.absolute? ? request_url : base_url + request_url
238
+ host = host_url(request)
239
+ url = request.absolute? ? request.url : host + request.url
228
240
 
229
241
  begin
230
- logger.info(request: { url: url, query: request.query, header: request_headers }) if logger
242
+ logger.info(request: { url: url, query: request.query, header: request_headers(request) }) if logger
231
243
  raw_response = yield(url)
232
244
  logger.debug(response: raw_response) if logger
233
245
  clear_headers
@@ -237,10 +249,7 @@ module Contentful
237
249
  reset_time = rate_limit_error.response.raw[RATE_LIMIT_RESET_HEADER_KEY].to_i
238
250
  if should_retry(retries_left, reset_time, configuration[:max_rate_limit_wait])
239
251
  retries_left -= 1
240
- retry_message = 'Contentful Management API Rate Limit Hit! '
241
- retry_message += "Retrying - Retries left: #{retries_left}"
242
- retry_message += "- Time until reset (seconds): #{reset_time}"
243
- logger.info(retry_message) if logger
252
+ logger.info(retry_message(retries_left, reset_time)) if logger
244
253
  sleep(reset_time * Random.new.rand(1.0..1.2))
245
254
  retry
246
255
  end
@@ -251,6 +260,20 @@ module Contentful
251
260
  result
252
261
  end
253
262
 
263
+ # @private
264
+ def host_url(request)
265
+ (%r{^/[\w|-]+/uploads(?:/[\w|-]*)?$} =~ request.url) ? uploads_url : base_url
266
+ end
267
+
268
+ # @private
269
+ def retry_message(retries_left, reset_time)
270
+ retry_message = 'Contentful Management API Rate Limit Hit! '
271
+ retry_message += "Retrying - Retries left: #{retries_left}"
272
+ retry_message += "- Time until reset (seconds): #{reset_time}"
273
+
274
+ retry_message
275
+ end
276
+
254
277
  # @private
255
278
  def should_retry(retries_left, reset_time, max_wait)
256
279
  retries_left > 0 && max_wait > reset_time
@@ -266,28 +289,28 @@ module Contentful
266
289
  # @private
267
290
  def delete(request)
268
291
  execute_request(request) do |url|
269
- self.class.delete_http(url, {}, request_headers, proxy_parameters)
292
+ self.class.delete_http(url, {}, request_headers(request), proxy_parameters)
270
293
  end
271
294
  end
272
295
 
273
296
  # @private
274
297
  def get(request)
275
298
  execute_request(request) do |url|
276
- self.class.get_http(url, request.query, request_headers, proxy_parameters)
299
+ self.class.get_http(url, request.query, request_headers(request), proxy_parameters)
277
300
  end
278
301
  end
279
302
 
280
303
  # @private
281
304
  def post(request)
282
305
  execute_request(request) do |url|
283
- self.class.post_http(url, request.query, request_headers, proxy_parameters)
306
+ self.class.post_http(url, request.query, request_headers(request), proxy_parameters)
284
307
  end
285
308
  end
286
309
 
287
310
  # @private
288
311
  def put(request)
289
312
  execute_request(request) do |url|
290
- self.class.put_http(url, request.query, request_headers, proxy_parameters)
313
+ self.class.put_http(url, request.query, request_headers(request), proxy_parameters)
291
314
  end
292
315
  end
293
316
 
@@ -296,6 +319,11 @@ module Contentful
296
319
  "#{protocol}://#{configuration[:api_url]}/spaces"
297
320
  end
298
321
 
322
+ # @private
323
+ def uploads_url
324
+ "#{protocol}://#{configuration[:uploads_url]}/spaces"
325
+ end
326
+
299
327
  # @private
300
328
  def default_locale
301
329
  configuration[:default_locale]
@@ -348,7 +376,7 @@ module Contentful
348
376
 
349
377
  # @todo headers should be supplied differently, maybe through the request object.
350
378
  # @private
351
- def request_headers
379
+ def request_headers(request = nil)
352
380
  headers = {}
353
381
  headers.merge! user_agent
354
382
  headers.merge! authentication_header
@@ -358,6 +386,8 @@ module Contentful
358
386
  headers.merge! zero_length_header if zero_length
359
387
  headers.merge! content_type_header(content_type_id) if content_type_id
360
388
  headers.merge! accept_encoding_header('gzip') if gzip_encoded
389
+
390
+ headers.merge! request.headers unless request.nil?
361
391
  headers
362
392
  end
363
393
 
@@ -0,0 +1,19 @@
1
+ require_relative 'client_association_methods_factory'
2
+
3
+ module Contentful
4
+ module Management
5
+ # Wrapper for Upload API for usage from within Client
6
+ # @private
7
+ class ClientUploadMethodsFactory
8
+ include Contentful::Management::ClientAssociationMethodsFactory
9
+
10
+ def new(*)
11
+ fail 'Not supported'
12
+ end
13
+
14
+ def all(*)
15
+ fail 'Not supported'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -14,17 +14,17 @@ module Contentful
14
14
  class ContentType
15
15
  # Shortcuts for Contentful Field Types
16
16
  FIELD_TYPES = [
17
- SYMBOL = 'Symbol',
18
- TEXT = 'Text',
19
- INTEGER = 'Integer',
20
- FLOAT = 'Number',
21
- DATE = 'Date',
22
- BOOLEAN = 'Boolean',
23
- LINK = 'Link',
24
- ARRAY = 'Array',
25
- OBJECT = 'Object',
26
- LOCATION = 'Location'
27
- ]
17
+ SYMBOL = 'Symbol'.freeze,
18
+ TEXT = 'Text'.freeze,
19
+ INTEGER = 'Integer'.freeze,
20
+ FLOAT = 'Number'.freeze,
21
+ DATE = 'Date'.freeze,
22
+ BOOLEAN = 'Boolean'.freeze,
23
+ LINK = 'Link'.freeze,
24
+ ARRAY = 'Array'.freeze,
25
+ OBJECT = 'Object'.freeze,
26
+ LOCATION = 'Location'.freeze
27
+ ].freeze
28
28
 
29
29
  include Contentful::Management::Resource
30
30
  include Contentful::Management::Resource::SystemProperties
@@ -42,9 +42,9 @@ module Contentful
42
42
  ClientContentTypeMethodsFactory
43
43
  end
44
44
 
45
- alias_method :activate, :publish
46
- alias_method :deactivate, :unpublish
47
- alias_method :active?, :published?
45
+ alias activate publish
46
+ alias deactivate unpublish
47
+ alias active? published?
48
48
 
49
49
  # @private
50
50
  def self.create_attributes(_client, attributes)
@@ -97,7 +97,7 @@ module Contentful
97
97
  end
98
98
 
99
99
  # @private
100
- alias_method :orig_fields, :fields
100
+ alias orig_fields fields
101
101
 
102
102
  # Use this method only in the context of content type.
103
103
  # Allows you to add and create a field with specified attributes or destroy by pass field id.
@@ -164,10 +164,10 @@ module Contentful
164
164
 
165
165
  def query_attributes(attributes)
166
166
  parameters = {}
167
- parameters.merge!(displayField: display_field_value(attributes))
168
- parameters.merge!(name: (attributes[:name] || name))
169
- parameters.merge!(description: (attributes[:description] || description))
170
- parameters.merge!(fields: self.class.fields_to_nested_properties_hash(attributes[:fields] || fields))
167
+ parameters[:displayField] = display_field_value(attributes)
168
+ parameters[:name] = attributes[:name] || name
169
+ parameters[:description] = attributes[:description] || description
170
+ parameters[:fields] = self.class.fields_to_nested_properties_hash(attributes[:fields] || fields)
171
171
 
172
172
  parameters.delete_if { |_, v| v.nil? }
173
173
  end