contentful-management 0.2.1 → 0.3.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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +37 -8
  3. data/Gemfile +0 -1
  4. data/README.md +130 -0
  5. data/Rakefile +0 -1
  6. data/contentful-management.gemspec +0 -1
  7. data/examples/blog.rb +1 -1
  8. data/lib/contentful/management.rb +0 -1
  9. data/lib/contentful/management/array.rb +0 -1
  10. data/lib/contentful/management/asset.rb +65 -26
  11. data/lib/contentful/management/client.rb +19 -9
  12. data/lib/contentful/management/content_type.rb +43 -28
  13. data/lib/contentful/management/dynamic_entry.rb +15 -15
  14. data/lib/contentful/management/entry.rb +73 -40
  15. data/lib/contentful/management/error.rb +6 -1
  16. data/lib/contentful/management/field.rb +63 -8
  17. data/lib/contentful/management/file.rb +0 -1
  18. data/lib/contentful/management/http_client.rb +0 -1
  19. data/lib/contentful/management/link.rb +0 -1
  20. data/lib/contentful/management/locale.rb +11 -3
  21. data/lib/contentful/management/location.rb +0 -1
  22. data/lib/contentful/management/request.rb +5 -7
  23. data/lib/contentful/management/resource.rb +3 -3
  24. data/lib/contentful/management/resource/array_like.rb +0 -1
  25. data/lib/contentful/management/resource/fields.rb +1 -2
  26. data/lib/contentful/management/resource/refresher.rb +3 -3
  27. data/lib/contentful/management/resource/system_properties.rb +0 -1
  28. data/lib/contentful/management/resource_builder.rb +16 -27
  29. data/lib/contentful/management/response.rb +36 -32
  30. data/lib/contentful/management/space.rb +16 -6
  31. data/lib/contentful/management/space_webhook_methods_factory.rb +0 -4
  32. data/lib/contentful/management/support.rb +0 -1
  33. data/lib/contentful/management/validation.rb +34 -0
  34. data/lib/contentful/management/version.rb +1 -2
  35. data/lib/contentful/management/webhook.rb +17 -10
  36. data/spec/fixtures/vcr_cassettes/content_type/validation/in.yml +588 -0
  37. data/spec/fixtures/vcr_cassettes/content_type/validation/in_add.yml +620 -0
  38. data/spec/fixtures/vcr_cassettes/content_type/validation/in_update.yml +668 -0
  39. data/spec/fixtures/vcr_cassettes/content_type/validation/link_content_type.yml +749 -0
  40. data/spec/fixtures/vcr_cassettes/content_type/validation/link_field.yml +770 -0
  41. data/spec/fixtures/vcr_cassettes/content_type/validation/link_mimetype_group.yml +766 -0
  42. data/spec/fixtures/vcr_cassettes/content_type/validation/multiple_add.yml +854 -0
  43. data/spec/fixtures/vcr_cassettes/content_type/validation/present.yml +808 -0
  44. data/spec/fixtures/vcr_cassettes/content_type/validation/range.yml +683 -0
  45. data/spec/fixtures/vcr_cassettes/content_type/validation/range_update.yml +697 -0
  46. data/spec/fixtures/vcr_cassettes/content_type/validation/regexp.yml +720 -0
  47. data/spec/fixtures/vcr_cassettes/content_type/validation/size.yml +791 -0
  48. data/spec/fixtures/vcr_cassettes/entry/service_unavailable.yml +52 -0
  49. data/spec/fixtures/vcr_cassettes/space/webhook/create.yml +439 -0
  50. data/spec/lib/contentful/management/asset_spec.rb +16 -16
  51. data/spec/lib/contentful/management/client_spec.rb +0 -1
  52. data/spec/lib/contentful/management/content_type_spec.rb +143 -1
  53. data/spec/lib/contentful/management/entry_spec.rb +10 -4
  54. data/spec/lib/contentful/management/locale_spec.rb +0 -1
  55. data/spec/lib/contentful/management/space_spec.rb +9 -1
  56. data/spec/lib/contentful/management/webhook_spec.rb +0 -1
  57. data/spec/spec_helper.rb +0 -1
  58. data/spec/support/vcr.rb +0 -1
  59. metadata +63 -62
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Contentful
3
2
  module Management
4
3
  # All errors raised by the contentful gem are either instances of Contentful::Error
@@ -25,6 +24,8 @@ module Contentful
25
24
  Unauthorized
26
25
  when 500
27
26
  ServerError
27
+ when 503
28
+ ServiceUnavailable
28
29
  else
29
30
  Error
30
31
  end
@@ -51,6 +52,10 @@ module Contentful
51
52
  class ServerError < Error
52
53
  end
53
54
 
55
+ # 503
56
+ class ServiceUnavailable < Error
57
+ end
58
+
54
59
  # Raised when response is no valid json
55
60
  class UnparsableJson < Error
56
61
  end
@@ -1,6 +1,5 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require_relative 'resource'
3
-
2
+ require_relative 'validation'
4
3
  module Contentful
5
4
  module Management
6
5
  # A ContentType's field schema
@@ -14,21 +13,77 @@ module Contentful
14
13
  property :items, Field
15
14
  property :required, :boolean
16
15
  property :localized, :boolean
16
+ property :validations, Validation
17
17
 
18
+ # Takes a field object of content type
19
+ # Merges existing properties, items and validations of field with new one
18
20
  def deep_merge!(field)
19
- properties.merge!(field.properties.select { |name, _type| name != :items })
20
- items.properties.merge!(field.items.properties) if items.respond_to?(:properties) && field.items.respond_to?(:properties)
21
+ merge_properties(field.properties)
22
+ merge_items(field.items)
23
+ merge_validations(field.validations)
21
24
  end
22
25
 
26
+ # Extract values of field to hash
23
27
  def properties_to_hash
24
28
  properties.each_with_object({}) do |(key, value), results|
25
- if key == :items
26
- results[key] = value.properties_to_hash if type == 'Array' && value.is_a?(Field)
29
+ results[key] = parse_value(key, value)
30
+ end
31
+ end
32
+
33
+ # Return parsed value of field object
34
+ def parse_value(key, value)
35
+ case key
36
+ when :items
37
+ value.properties_to_hash if type == 'Array' && type.is_a?(Field)
38
+ when :validations
39
+ validations_to_hash(value) if value.is_a?(::Array)
27
40
  else
28
- results[key] = value if !value.nil? && (value.respond_to?(:empty?) && !value.empty? || !value.respond_to?(:empty?) && value)
29
- end
41
+ value if self.class.value_exists?(value)
42
+ end
43
+ end
44
+
45
+ def self.value_exists?(value)
46
+ value.respond_to?(:empty?) && !value.empty? || !value.respond_to?(:empty?) && value
47
+ end
48
+
49
+ private
50
+
51
+ # Update properties of field object
52
+ def merge_properties(new_properties)
53
+ properties.merge!(new_properties.select { |name, _type| name != :items && name != :validations })
54
+ end
55
+
56
+ # Update items of field object
57
+ def merge_items(new_items)
58
+ items.properties.merge!(new_items.properties) if items.respond_to?(:properties) && new_items.respond_to?(:properties)
59
+ end
60
+
61
+ # Takes an array with new validations
62
+ # Returns merged existing and new validations
63
+ def merge_validations(new_validations)
64
+ if new_validations
65
+ validations_by_type = validations_by_type(validations)
66
+ new_validations_by_type = validations_by_type(new_validations)
67
+ validations_by_type.delete_if { |type, _v| new_validations_by_type[type] }
68
+ self.validations = validations_by_type.values + new_validations_by_type.values
30
69
  end
31
70
  end
71
+
72
+ def validations_by_type(validations)
73
+ validations.is_a?(::Array) ? index_by_type(validations) : {}
74
+ end
75
+
76
+ # Build hash with validations
77
+ def index_by_type(validations)
78
+ validations.each_with_object({}) { |validation, results| results[validation.type] = validation }
79
+ end
80
+
81
+ def validations_to_hash(validations)
82
+ validations.each_with_object([]) do |validation, results|
83
+ results << validation.properties_to_hash
84
+ end
85
+ end
86
+
32
87
  end
33
88
  end
34
89
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require_relative 'resource'
3
2
 
4
3
  module Contentful
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Contentful
3
2
  module Management
4
3
  module HTTPClient
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require_relative 'resource'
3
2
 
4
3
  module Contentful
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require_relative 'resource'
3
2
 
4
3
  module Contentful
@@ -44,7 +43,11 @@ module Contentful
44
43
  # :publish
45
44
  # Returns a Contentful::Management::Locale.
46
45
  def self.create(space_id, attributes)
47
- request = Request.new("/#{ space_id }/locales", 'name' => attributes.fetch(:name), 'code' => attributes.fetch(:code))
46
+ request = Request.new(
47
+ "/#{ space_id }/locales",
48
+ 'name' => attributes.fetch(:name),
49
+ 'code' => attributes.fetch(:code)
50
+ )
48
51
  response = request.post
49
52
  result = ResourceBuilder.new(response, {'Locale' => Locale}, {})
50
53
  result.run
@@ -54,7 +57,12 @@ module Contentful
54
57
  # Takes a hash with attributes.
55
58
  # Returns a Contentful::Management::Locale.
56
59
  def update(attributes)
57
- request = Request.new("/#{ space.id }/locales/#{ id }", {'name' => attributes.fetch(:name)}, id = nil, version: sys[:version])
60
+ request = Request.new(
61
+ "/#{ space.id }/locales/#{ id }",
62
+ {'name' => attributes.fetch(:name)},
63
+ id = nil,
64
+ version: sys[:version]
65
+ )
58
66
  response = request.put
59
67
  result = ResourceBuilder.new(response, {'Locale' => Locale}, {})
60
68
  refresh_data(result.run)
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require_relative 'resource'
3
2
 
4
3
  module Contentful
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Contentful
3
2
  module Management
4
3
  # This object represents a request that is to be made. It gets initialized by the client
@@ -11,9 +10,9 @@ module Contentful
11
10
  @header = header
12
11
  @initial_id = id
13
12
  @client = Contentful::Management::Client.shared_instance
14
- @client.version = header[:version] if header[:version]
15
- @client.organization_id = header[:organization_id] if header[:organization_id]
16
- @client.content_type_id = header[:content_type_id] if header[:content_type_id]
13
+ @client.version = header[:version]
14
+ @client.organization_id = header[:organization_id]
15
+ @client.content_type_id = header[:content_type_id]
17
16
  @client.zero_length = query.empty?
18
17
  @endpoint = endpoint
19
18
  @absolute = true if @endpoint.start_with?('http')
@@ -71,9 +70,8 @@ module Contentful
71
70
  Hash[
72
71
  query.map do |key, value|
73
72
  [
74
- key.to_sym,
75
- value
76
- # value.is_a?(::Array) ? value.join(',') : value
73
+ key.to_sym,
74
+ value
77
75
  ]
78
76
  end
79
77
  ]
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require_relative 'resource/system_properties'
3
2
  require_relative 'resource/refresher'
4
3
  require 'date'
@@ -22,7 +21,7 @@ module Contentful
22
21
  date: ->(value) { !value.nil? ? DateTime.parse(value) : nil }
23
22
  }
24
23
 
25
- attr_reader :properties, :request, :client, :default_locale
24
+ attr_reader :properties, :request, :client, :default_locale, :raw_object
26
25
 
27
26
  def initialize(object = nil, request = nil, client = nil, nested_locale_fields = false, default_locale = Contentful::Management::Client::DEFAULT_CONFIGURATION[:default_locale])
28
27
  self.class.update_coercions!
@@ -32,6 +31,7 @@ module Contentful
32
31
  @properties = extract_from_object object, :property, self.class.property_coercions.keys
33
32
  @request = request
34
33
  @client = client
34
+ @raw_object = object
35
35
  end
36
36
 
37
37
  def inspect(info = nil)
@@ -82,7 +82,7 @@ module Contentful
82
82
 
83
83
  def coerce_value_or_array(value, what = nil)
84
84
  if value.is_a? ::Array
85
- value.map { |v| coerce_or_create_class(v, what) }
85
+ value.map { |row| coerce_or_create_class(row, what) }
86
86
  else
87
87
  coerce_or_create_class(value, what)
88
88
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Contentful
3
2
  module Management
4
3
  module Resource
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require_relative '../file'
3
2
 
4
3
  module Contentful
@@ -40,7 +39,7 @@ module Contentful
40
39
  end
41
40
  base.send :define_method, "#{ accessor_name }_with_locales=" do |values|
42
41
  values.each do |locale, value|
43
- @fields[locale] = {} if @fields[locale].nil?
42
+ @fields[locale] = {} unless @fields[locale]
44
43
  @fields[locale][name.to_sym] = value
45
44
  end
46
45
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Contentful
3
2
  module Management
4
3
  module Resource
@@ -7,8 +6,9 @@ module Contentful
7
6
  # Reload an object
8
7
  # Updates the current version of the object to the version on the system
9
8
  def reload
10
- resource = self.is_a?(Space) ? self.class.find(id) : self.class.find(space.id, id)
11
- refresh_data(resource) if resource.is_a? self.class
9
+ self_class = self.class
10
+ resource = self.is_a?(Space) ? self_class.find(id) : self_class.find(space.id, id)
11
+ refresh_data(resource) if resource.is_a? self_class
12
12
  end
13
13
 
14
14
  def refresh_data(resource)
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Contentful
3
2
  module Management
4
3
  module Resource
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require_relative 'error'
3
2
  require_relative 'resource'
4
3
  require_relative 'entry'
@@ -16,13 +15,13 @@ module Contentful
16
15
  # See example/resource_mapping.rb for avanced usage
17
16
  class ResourceBuilder
18
17
  DEFAULT_RESOURCE_MAPPING = {
19
- 'Space' => Contentful::Management::Space,
20
- 'ContentType' => Contentful::Management::ContentType,
21
- 'Entry' => :find_entry_class,
22
- 'Asset' => Contentful::Management::Asset,
23
- 'Array' => :array_or_sync_page,
24
- 'Link' => Contentful::Management::Link,
25
- 'WebhookDefinition' => Contentful::Management::Webhook
18
+ 'Space' => Contentful::Management::Space,
19
+ 'ContentType' => Contentful::Management::ContentType,
20
+ 'Entry' => :find_entry_class,
21
+ 'Asset' => Contentful::Management::Asset,
22
+ 'Array' => :array_or_sync_page,
23
+ 'Link' => Contentful::Management::Link,
24
+ 'WebhookDefinition' => Contentful::Management::Webhook
26
25
  }
27
26
  DEFAULT_ENTRY_MAPPING = {}
28
27
 
@@ -32,7 +31,7 @@ module Contentful
32
31
  @response = response
33
32
  @client = Contentful::Management::Client.shared_instance
34
33
  @included_resources = {}
35
- @known_resources = Hash.new { |h, k| h[k] = {} }
34
+ @known_resources = Hash.new { |hash, key| hash[key] = {} }
36
35
  @nested_locales = true
37
36
  @default_locale = (client.configuration || Contentful::Client::DEFAULT_CONFIGURATION)[:default_locale]
38
37
  @resource_mapping = default_resource_mapping.merge(resource_mapping)
@@ -42,19 +41,10 @@ module Contentful
42
41
  # Starts the parsing process.
43
42
  # Either returns an Error, or the parsed Resource
44
43
  def run
45
- case response.status
46
- when :contentful_error
47
- Error[response.raw.status].new(response)
48
- when :unparsable_json
49
- UnparsableJson.new(response)
50
- when :not_contentful
51
- Error.new(response)
52
- else
53
- begin
54
- create_all_resources!
55
- rescue UnparsableResource => error
56
- error
57
- end
44
+ if response.status == :ok
45
+ create_all_resources!
46
+ else
47
+ response.object
58
48
  end
59
49
  end
60
50
 
@@ -75,6 +65,8 @@ module Contentful
75
65
  end
76
66
 
77
67
  @resource
68
+ rescue UnparsableResource => error
69
+ error
78
70
  end
79
71
 
80
72
  # Creates a single resource from the response object
@@ -109,10 +101,7 @@ module Contentful
109
101
 
110
102
  # Returns the id of the related ContentType, if there is one
111
103
  def content_type_id_for_entry(object)
112
- object['sys'] &&
113
- object['sys']['contentType'] &&
114
- object['sys']['contentType']['sys'] &&
115
- object['sys']['contentType']['sys']['id']
104
+ object['sys']['contentType']['sys']['id']
116
105
  end
117
106
 
118
107
  # Detects if a resource is an Contentful::Array or a SyncPage
@@ -159,7 +148,7 @@ module Contentful
159
148
 
160
149
  def detect_child_objects(object)
161
150
  if object.is_a? Hash
162
- object.select { |_, value| value.is_a?(Hash) && value.key?('sys') }
151
+ object.select { |_key, value| value.is_a?(Hash) && value.key?('sys') }
163
152
  else
164
153
  {}
165
154
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require_relative 'error'
3
2
  require 'multi_json'
4
3
 
@@ -29,60 +28,65 @@ module Contentful
29
28
  @request = request
30
29
  @status = :ok
31
30
 
32
- if service_unavailable_response?
33
- @status = :service_unavailable
34
- @error_message = 'Service Unavailable, contenful.com API seems to be down'
31
+ if valid_http_response?
32
+ parse_json!
35
33
  elsif no_content_response?
36
34
  @status = :no_content
37
- @object = true
38
- elsif parse_json!
39
- parse_contentful_error!
35
+ elsif no_resource_or_bad_request?
36
+ parse_contentful_error
37
+ else
38
+ parse_http_error
40
39
  end
41
40
  end
42
41
 
43
42
  private
44
43
 
45
- def service_unavailable_response?
46
- @raw.status == 503
44
+ def error_object?
45
+ object['sys']['type'] == 'Error'
46
+ end
47
+
48
+ def parse_contentful_error
49
+ @object = load_json
50
+ @error_message = object['message'] if error_object?
51
+ parse_http_error
52
+ end
53
+
54
+ def valid_http_response?
55
+ [200, 201].include?(raw.status)
56
+ end
57
+
58
+ def parse_http_error
59
+ @status = :error
60
+ @object = Error[raw.status].new(self)
61
+ end
62
+
63
+ def no_resource_or_bad_request?
64
+ [400, 404].include?(raw.status)
47
65
  end
48
66
 
49
67
  def no_content_response?
50
- @raw.to_s == '' && @raw.status == 204
68
+ raw.to_s == '' && raw.status == 204
51
69
  end
52
70
 
53
71
  def parse_json!
54
- body = unzip_response(raw)
55
- @object = MultiJson.load(body)
56
- true
72
+ @object = load_json
57
73
  rescue MultiJson::LoadError => error
58
- @status = :unparsable_json
59
74
  @error_message = error.message
60
- @object = error
61
- false
75
+ UnparsableJson.new(self)
62
76
  end
63
77
 
64
- def parse_contentful_error!
65
- if @object && @object['sys']
66
- if @object['sys']['type'] == 'Error'
67
- @status = :contentful_error
68
- @error_message = object['message']
69
- true
70
- else
71
- false
72
- end
73
- else
74
- @status = :not_contentful
75
- @error_message = 'No contentful system properties found in object'
76
- end
78
+ def load_json
79
+ MultiJson.load(unzip_response(raw))
77
80
  end
78
81
 
79
82
  def unzip_response(response)
80
- if response.headers['Content-Encoding'].eql?('gzip') then
81
- sio = StringIO.new(response.to_s)
83
+ parsed_response = response.to_s
84
+ if response.headers['Content-Encoding'].eql?('gzip')
85
+ sio = StringIO.new(parsed_response)
82
86
  gz = Zlib::GzipReader.new(sio)
83
87
  gz.read
84
88
  else
85
- response.to_s
89
+ parsed_response
86
90
  end
87
91
  end
88
92
  end