-
1
require 'contentful/version'
-
1
require 'contentful/support'
-
1
require 'contentful/client'
-
1
require_relative 'base_resource'
-
1
require_relative 'array_like'
-
-
1
module Contentful
-
# Resource Class for Arrays (e.g. search results)
-
# @see _ https://www.contentful.com/developers/documentation/content-delivery-api/#arrays
-
# @note It also provides an #each method and includes Ruby's Enumerable module (gives you methods like #min, #first, etc)
-
1
class Array < BaseResource
-
# @private
-
1
DEFAULT_LIMIT = 100
-
-
1
include Contentful::ArrayLike
-
-
1
attr_reader :total, :limit, :skip, :items, :endpoint
-
-
1
def initialize(item = nil,
-
default_locale = Contentful::Client::DEFAULT_CONFIGURATION[:default_locale],
-
endpoint = '', *)
-
69
super(item, { default_locale: default_locale })
-
-
69
@endpoint = endpoint
-
69
@total = item.fetch('total', nil)
-
69
@limit = item.fetch('limit', nil)
-
69
@skip = item.fetch('skip', nil)
-
69
@items = item.fetch('items', [])
-
end
-
-
# @private
-
1
def inspect
-
"<#{repr_name} total=#{total} skip=#{skip} limit=#{limit}>"
-
end
-
-
# Simplifies pagination
-
#
-
# @return [Contentful::Array, false]
-
1
def next_page(client = nil)
-
1
return false if client.nil?
-
-
1
new_skip = (skip || 0) + (limit || DEFAULT_LIMIT)
-
1
client.send(endpoint.delete('/'), limit: limit, skip: new_skip)
-
end
-
end
-
end
-
1
module Contentful
-
# Useful methods for array-like resources that can be included if an
-
# :items property exists
-
1
module ArrayLike
-
1
include Enumerable
-
-
# Returns true for array-like resources
-
#
-
# @return [true]
-
1
def array?
-
true
-
end
-
-
# Delegates to items#each
-
#
-
# @yield [Contentful::Entry, Contentful::Asset]
-
1
def each_item(&block)
-
59
items.each(&block)
-
end
-
1
alias each each_item
-
-
# Delegates to items#empty?
-
#
-
# @return [Boolean]
-
1
def empty?
-
items.empty?
-
end
-
-
# Delegetes to items#size
-
#
-
# @return [Number]
-
1
def size
-
items.size
-
end
-
1
alias length size
-
-
# Delegates to items#[]
-
#
-
# @return [Contentful::Entry, Contentful::Asset]
-
1
def [](index)
-
items[index]
-
end
-
-
# Delegates to items#last
-
#
-
# @return [Contentful::Entry, Contentful::Asset]
-
1
def last
-
items.last
-
end
-
end
-
end
-
1
require_relative 'fields_resource'
-
1
require_relative 'file'
-
-
1
module Contentful
-
# Resource class for Asset.
-
# https://www.contentful.com/developers/documentation/content-delivery-api/#assets
-
1
class Asset < FieldsResource
-
# @private
-
1
def marshal_dump
-
7
raw
-
end
-
-
# @private
-
1
def marshal_load(raw_object)
-
7
super(raw_object)
-
7
create_files!
-
7
define_asset_methods!
-
end
-
-
# @private
-
1
def inspect
-
"<#{repr_name} id='#{sys[:id]}' url='#{url}'>"
-
end
-
-
1
def initialize(*)
-
1257
super
-
1257
create_files!
-
1257
define_asset_methods!
-
end
-
-
# Generates a URL for the Contentful Image API
-
#
-
# @param [Hash] options
-
# @option options [Integer] :width
-
# @option options [Integer] :height
-
# @option options [String] :format
-
# @option options [String] :quality
-
# @option options [String] :focus
-
# @option options [String] :fit
-
# @option options [String] :fl File Layering - 'progressive'
-
# @see _ https://www.contentful.com/developers/documentation/content-delivery-api/#image-asset-resizing
-
#
-
# @return [String] Image API URL
-
1
def image_url(options = {})
-
5
query = {
-
w: options[:w] || options[:width],
-
h: options[:h] || options[:height],
-
fm: options[:fm] || options[:format],
-
q: options[:q] || options[:quality],
-
f: options[:f] || options[:focus],
-
fit: options[:fit],
-
fl: options[:fl]
-
35
}.reject { |_k, v| v.nil? }
-
-
5
if query.empty?
-
3
file.url
-
else
-
2
"#{file.url}?#{URI.encode_www_form(query)}"
-
end
-
end
-
-
1
alias url image_url
-
-
1
private
-
-
1
def create_files!
-
1264
file_json = fields[:file]
-
1264
return if file_json.nil?
-
-
2518
is_localized = file_json.keys.none? { |f| %w(fileName contentType details url).include? f }
-
1259
if is_localized
-
locales.each do |locale|
-
fields(locale)[:file] = ::Contentful::File.new(file_json[locale.to_s] || {})
-
end
-
else
-
1259
fields[:file] = ::Contentful::File.new(file_json)
-
end
-
end
-
-
1
def define_asset_methods!
-
1264
define_singleton_method :description do
-
fields.fetch(:description, nil)
-
end
-
-
1264
define_singleton_method :file do |wanted_locale = nil|
-
23
fields(wanted_locale)[:file]
-
end
-
end
-
end
-
end
-
1
require_relative 'support'
-
-
1
module Contentful
-
# Base definition of a Contentful Resource containing Sys properties
-
1
class BaseResource
-
1
attr_reader :raw, :default_locale, :sys
-
-
1
def initialize(item, configuration = {}, _localized = false, _includes = [], depth = 0)
-
7127
@raw = item
-
7127
@default_locale = configuration[:default_locale]
-
7127
@depth = depth
-
7127
@sys = hydrate_sys
-
7127
@configuration = configuration
-
-
7127
define_sys_methods!
-
end
-
-
# @private
-
1
def inspect
-
"<#{repr_name} id='#{sys[:id]}'>"
-
end
-
-
# Definition of equality
-
1
def ==(other)
-
1
self.class == other.class && sys[:id] == other.sys[:id]
-
end
-
-
# @private
-
1
def marshal_dump
-
raw
-
end
-
-
# @private
-
1
def marshal_load(raw_object)
-
22
@raw = raw_object
-
22
@sys = hydrate_sys
-
22
@depth = 0
-
22
define_sys_methods!
-
end
-
-
# Issues the request that was made to fetch this response again.
-
# Only works for Entry, Asset, ContentType and Space
-
1
def reload(client = nil)
-
1
return client.send(Support.snakify(self.class.name.split('::').last), id) unless client.nil?
-
-
1
false
-
end
-
-
1
private
-
-
1
def define_sys_methods!
-
7149
@sys.each do |k, v|
-
32016
define_singleton_method k do
-
14302
v
-
end
-
end
-
end
-
-
1
def hydrate_sys
-
7149
result = {}
-
7149
raw.fetch('sys', {}).each do |k, v|
-
32016
if %w(space contentType).include?(k)
-
4137
v = build_link(v)
-
elsif %w(createdAt updatedAt deletedAt).include?(k)
-
5555
v = DateTime.parse(v)
-
end
-
32016
result[Support.snakify(k).to_sym] = v
-
end
-
7149
result
-
end
-
-
1
protected
-
-
1
def repr_name
-
self.class
-
end
-
-
1
def internal_resource_locale
-
8027
sys.fetch(:locale, nil) || default_locale
-
end
-
-
1
def build_link(item)
-
4270
require_relative 'link'
-
4270
::Contentful::Link.new(item)
-
end
-
end
-
end
-
1
require_relative 'request'
-
1
require_relative 'response'
-
1
require_relative 'resource_builder'
-
1
require_relative 'sync'
-
1
require_relative 'content_type_cache'
-
-
1
require 'http'
-
1
require 'logger'
-
-
1
module Contentful
-
# The client object is initialized with a space and a key and then used
-
# for querying resources from this space.
-
# See README for details
-
1
class Client
-
# Default configuration for Contentful::Client
-
1
DEFAULT_CONFIGURATION = {
-
secure: true,
-
raise_errors: true,
-
dynamic_entries: :manual,
-
api_url: 'cdn.contentful.com',
-
api_version: 1,
-
authentication_mechanism: :header,
-
resource_builder: ResourceBuilder,
-
resource_mapping: {},
-
entry_mapping: {},
-
default_locale: 'en-US',
-
raw_mode: false,
-
gzip_encoded: true,
-
logger: false,
-
log_level: Logger::INFO,
-
proxy_host: nil,
-
proxy_username: nil,
-
proxy_password: nil,
-
proxy_port: nil,
-
max_rate_limit_retries: 1,
-
max_rate_limit_wait: 60,
-
max_include_resolution_depth: 20
-
}
-
# Rate Limit Reset Header Key
-
1
RATE_LIMIT_RESET_HEADER_KEY = 'x-contentful-ratelimit-reset'
-
-
1
attr_reader :configuration, :logger, :proxy
-
-
# Wraps the actual HTTP request via proxy
-
# @private
-
1
def self.get_http(url, query, headers = {}, proxy = {})
-
174
if proxy[:host]
-
HTTP[headers].via(proxy[:host], proxy[:port], proxy[:username], proxy[:password]).get(url, params: query)
-
else
-
174
HTTP[headers].get(url, params: query)
-
end
-
end
-
-
# @see _ https://github.com/contentful/contentful.rb#client-configuration-options
-
# @param [Hash] given_configuration
-
# @option given_configuration [String] :space Required
-
# @option given_configuration [String] :access_token Required
-
# @option given_configuration [String] :api_url Modifying this to 'preview.contentful.com' gives you access to our Preview API
-
# @option given_configuration [String] :api_version
-
# @option given_configuration [String] :default_locale
-
# @option given_configuration [String] :proxy_host
-
# @option given_configuration [String] :proxy_username
-
# @option given_configuration [String] :proxy_password
-
# @option given_configuration [Number] :proxy_port
-
# @option given_configuration [Number] :max_rate_limit_retries
-
# @option given_configuration [Number] :max_rate_limit_wait
-
# @option given_configuration [Number] :max_include_resolution_depth
-
# @option given_configuration [Boolean] :gzip_encoded
-
# @option given_configuration [Boolean] :raw_mode
-
# @option given_configuration [false, ::Logger] :logger
-
# @option given_configuration [::Logger::DEBUG, ::Logger::INFO, ::Logger::WARN, ::Logger::ERROR] :log_level
-
# @option given_configuration [Boolean] :raise_errors
-
# @option given_configuration [::Array<String>] :dynamic_entries
-
# @option given_configuration [::Hash<String, Contentful::Resource>] :resource_mapping
-
# @option given_configuration [::Hash<String, Contentful::Resource>] :entry_mapping
-
1
def initialize(given_configuration = {})
-
181
@configuration = default_configuration.merge(given_configuration)
-
181
normalize_configuration!
-
181
validate_configuration!
-
179
setup_logger
-
-
179
update_dynamic_entry_cache! if configuration[:dynamic_entries] == :auto
-
end
-
-
# @private
-
1
def setup_logger
-
179
@logger = configuration[:logger]
-
179
logger.level = configuration[:log_level] if logger
-
end
-
-
# @private
-
1
def proxy_params
-
{
-
host: configuration[:proxy_host],
-
port: configuration[:proxy_port],
-
username: configuration[:proxy_username],
-
password: configuration[:proxy_password]
-
180
}
-
end
-
-
# Returns the default configuration
-
# @private
-
1
def default_configuration
-
181
DEFAULT_CONFIGURATION.dup
-
end
-
-
# Gets the client's space
-
#
-
# @param [Hash] query
-
#
-
# @return [Contentful::Space]
-
1
def space(query = {})
-
9
Request.new(self, '', query).get
-
end
-
-
# Gets a specific content type
-
#
-
# @param [String] id
-
# @param [Hash] query
-
#
-
# @return [Contentful::ContentType]
-
1
def content_type(id, query = {})
-
22
Request.new(self, '/content_types', query, id).get
-
end
-
-
# Gets a collection of content types
-
#
-
# @param [Hash] query
-
#
-
# @return [Contentful::Array<Contentful::ContentType>]
-
1
def content_types(query = {})
-
20
Request.new(self, '/content_types', query).get
-
end
-
-
# Gets a specific entry
-
#
-
# @param [String] id
-
# @param [Hash] query
-
#
-
# @return [Contentful::Entry]
-
1
def entry(id, query = {})
-
29
normalize_select!(query)
-
29
query['sys.id'] = id
-
29
entries = Request.new(self, '/entries', query).get
-
-
26
return entries if configuration[:raw_mode]
-
-
25
entries.first
-
end
-
-
# Gets a collection of entries
-
#
-
# @param [Hash] query
-
#
-
# @return [Contentful::Array<Contentful::Entry>]
-
1
def entries(query = {})
-
16
normalize_select!(query)
-
16
Request.new(self, '/entries', query).get
-
end
-
-
# Gets a specific asset
-
#
-
# @param [String] id
-
# @param [Hash] query
-
#
-
# @return [Contentful::Asset]
-
1
def asset(id, query = {})
-
20
Request.new(self, '/assets', query, id).get
-
end
-
-
# Gets a collection of assets
-
#
-
# @param [Hash] query
-
#
-
# @return [Contentful::Array<Contentful::Asset>]
-
1
def assets(query = {})
-
7
normalize_select!(query)
-
7
Request.new(self, '/assets', query).get
-
end
-
-
# Returns the base url for all of the client's requests
-
# @private
-
1
def base_url
-
164
"http#{configuration[:secure] ? 's' : ''}://#{configuration[:api_url]}/spaces/#{configuration[:space]}"
-
end
-
-
# Returns the headers used for the HTTP requests
-
# @private
-
1
def request_headers
-
185
headers = { 'User-Agent' => "RubyContentfulGem/#{Contentful::VERSION}" }
-
185
headers['Authorization'] = "Bearer #{configuration[:access_token]}" if configuration[:authentication_mechanism] == :header
-
185
headers['Content-Type'] = "application/vnd.contentful.delivery.v#{configuration[:api_version].to_i}+json" if configuration[:api_version]
-
185
headers['Accept-Encoding'] = 'gzip' if configuration[:gzip_encoded]
-
185
headers
-
end
-
-
# Patches a query hash with the client configurations for queries
-
# @private
-
1
def request_query(query)
-
178
if configuration[:authentication_mechanism] == :query_string
-
1
query['access_token'] = configuration[:access_token]
-
end
-
178
query
-
end
-
-
# Get a Contentful::Request object
-
# Set second parameter to false to deactivate Resource building and
-
# return Response objects instead
-
#
-
# @private
-
1
def get(request, build_resource = true)
-
175
retries_left = configuration[:max_rate_limit_retries]
-
175
result = nil
-
175
begin
-
176
response = run_request(request)
-
-
176
return response if !build_resource || configuration[:raw_mode]
-
-
171
return fail_response(response) if response.status != :ok
-
-
162
result = do_build_resource(response)
-
rescue UnparsableResource => error
-
raise error if configuration[:raise_errors]
-
return error
-
rescue Contentful::RateLimitExceeded => rate_limit_error
-
2
reset_time = rate_limit_error.response.raw[RATE_LIMIT_RESET_HEADER_KEY].to_i
-
2
if should_retry(retries_left, reset_time, configuration[:max_rate_limit_wait])
-
1
retries_left -= 1
-
1
logger.info(retry_message(retries_left, reset_time)) if logger
-
1
sleep(reset_time * Random.new.rand(1.0..1.2))
-
1
retry
-
end
-
-
1
raise
-
end
-
-
162
result
-
end
-
-
# @private
-
1
def retry_message(retries_left, reset_time)
-
1
message = 'Contentful API Rate Limit Hit! '
-
1
message += "Retrying - Retries left: #{retries_left}"
-
1
message += "- Time until reset (seconds): #{reset_time}"
-
1
message
-
end
-
-
# @private
-
1
def fail_response(response)
-
9
fail response.object if configuration[:raise_errors]
-
1
response.object
-
end
-
-
# @private
-
1
def should_retry(retries_left, reset_time, max_wait)
-
2
retries_left > 0 && max_wait > reset_time
-
end
-
-
# Runs request and parses Response
-
# @private
-
1
def run_request(request)
-
176
url = request.absolute? ? request.url : base_url + request.url
-
176
logger.info(request: { url: url, query: request.query, header: request_headers }) if logger
-
176
Response.new(
-
self.class.get_http(
-
url,
-
request_query(request.query),
-
request_headers,
-
proxy_params
-
), request
-
)
-
end
-
-
# Runs Resource Builder
-
# @private
-
1
def do_build_resource(response)
-
162
logger.debug(response: response) if logger
-
configuration[:resource_builder].new(
-
response.object,
-
configuration,
-
162
(response.request.query || {}).fetch(:locale, nil) == '*',
-
0,
-
response.request.endpoint
-
162
).run
-
end
-
-
# Use this method together with the client's :dynamic_entries configuration.
-
# See README for details.
-
# @private
-
1
def update_dynamic_entry_cache!
-
10
content_types(limit: 1000).map do |ct|
-
21
ContentTypeCache.cache_set(configuration[:space], ct.id, ct)
-
end
-
end
-
-
# Use this method to manually register a dynamic entry
-
# See examples/dynamic_entries.rb
-
# @private
-
1
def register_dynamic_entry(key, klass)
-
1
ContentTypeCache.cache_set(configuration[:space], key, klass)
-
end
-
-
# Create a new synchronisation object
-
#
-
# @param [Hash, String] options Options or Sync URL
-
#
-
# @note You will need to call #each_page or #first_page on it
-
#
-
# @return [Contentful::Sync]
-
1
def sync(options = { initial: true })
-
40
Sync.new(self, options)
-
end
-
-
1
private
-
-
# If the query contains the :select operator, we enforce :sys properties.
-
# The SDK requires sys.type to function properly, but as other of our SDKs
-
# require more parts of the :sys properties, we decided that every SDK should
-
# include the complete :sys block to provide consistency accross our SDKs.
-
1
def normalize_select!(query)
-
52
return unless query.key?(:select)
-
-
9
query[:select] = query[:select].split(',').map(&:strip) if query[:select].is_a? String
-
19
query[:select] = query[:select].reject { |p| p.start_with?('sys.') }
-
9
query[:select] << 'sys' unless query[:select].include?('sys')
-
end
-
-
1
def normalize_configuration!
-
905
[:space, :access_token, :api_url, :default_locale].each { |s| configuration[s] = configuration[s].to_s }
-
181
configuration[:authentication_mechanism] = configuration[:authentication_mechanism].to_sym
-
end
-
-
1
def validate_configuration!
-
181
fail ArgumentError, 'You will need to initialize a client with a :space' if configuration[:space].empty?
-
180
fail ArgumentError, 'You will need to initialize a client with an :access_token' if configuration[:access_token].empty?
-
179
fail ArgumentError, 'The client configuration needs to contain an :api_url' if configuration[:api_url].empty?
-
179
fail ArgumentError, 'The client configuration needs to contain a :default_locale' if configuration[:default_locale].empty?
-
179
fail ArgumentError, 'The :api_version must be a positive number or nil' unless configuration[:api_version].to_i >= 0
-
179
fail ArgumentError, 'The authentication mechanism must be :header or :query_string' unless [:header, :query_string].include?(
-
configuration[:authentication_mechanism]
-
)
-
179
fail ArgumentError, 'The :dynamic_entries mode must be :auto or :manual' unless [:auto, :manual].include?(
-
configuration[:dynamic_entries]
-
)
-
end
-
end
-
end
-
1
require_relative 'base_resource'
-
1
require_relative 'field'
-
1
require_relative 'support'
-
-
1
module Contentful
-
# Resource Class for Content Types
-
# https://www.contentful.com/developers/documentation/content-delivery-api/#content-types
-
1
class ContentType < BaseResource
-
1
attr_reader :name, :description, :fields, :display_field
-
-
1
def initialize(item, *)
-
84
super
-
-
84
@name = item.fetch('name', nil)
-
84
@description = item.fetch('description', nil)
-
538
@fields = item.fetch('fields', []).map { |field| Field.new(field) }
-
84
@display_field = item.fetch('displayField', nil)
-
end
-
-
# Field definition for field
-
1
def field_for(field_id)
-
20111
fields.detect { |f| Support.snakify(f.id) == Support.snakify(field_id) }
-
end
-
-
1
protected
-
-
1
def repr_name
-
"#{super}[#{name}]"
-
end
-
end
-
end
-
1
module Contentful
-
# Cache for Content Types
-
1
class ContentTypeCache
-
1
@cache = {}
-
-
1
class << self
-
1
attr_reader :cache
-
end
-
-
# Clears the Content Type Cache
-
1
def self.clear!
-
19
@cache = {}
-
end
-
-
# Gets a Content Type from the Cache
-
1
def self.cache_get(space_id, content_type_id)
-
7113
@cache.fetch(space_id, {}).fetch(content_type_id.to_sym, nil)
-
end
-
-
# Sets a Content Type in the Cache
-
1
def self.cache_set(space_id, content_type_id, klass)
-
22
@cache[space_id] ||= {}
-
22
@cache[space_id][content_type_id.to_sym] = klass
-
end
-
end
-
end
-
1
require_relative 'base_resource'
-
-
1
module Contentful
-
# Resource class for deleted entries
-
# https://www.contentful.com/developers/documentation/content-delivery-api/http/#sync-item-types
-
1
class DeletedAsset < BaseResource; end
-
end
-
1
require_relative 'base_resource'
-
-
1
module Contentful
-
# Resource class for deleted entries
-
# https://www.contentful.com/developers/documentation/content-delivery-api/http/#sync-item-types
-
1
class DeletedEntry < BaseResource; end
-
end
-
1
require_relative 'fields_resource'
-
1
require_relative 'content_type_cache'
-
-
1
module Contentful
-
# Resource class for Entry.
-
# @see _ https://www.contentful.com/developers/documentation/content-delivery-api/#entries
-
1
class Entry < FieldsResource
-
# Returns true for resources that are entries
-
1
def entry?
-
4
true
-
end
-
-
1
private
-
-
1
def coerce(field_id, value, localized, includes)
-
9563
return build_nested_resource(value, localized, includes) if Support.link?(value)
-
7125
return coerce_link_array(value, localized, includes) if Support.link_array?(value)
-
-
7113
content_type = ContentTypeCache.cache_get(sys[:space].id, sys[:content_type].id)
-
-
7113
unless content_type.nil?
-
4554
content_type_field = content_type.field_for(field_id)
-
4554
return content_type_field.coerce(value) unless content_type_field.nil?
-
end
-
-
2562
super(field_id, value, localized, includes)
-
end
-
-
1
def coerce_link_array(value, localized, includes)
-
12
items = []
-
12
value.each do |link|
-
23
items << build_nested_resource(link, localized, includes)
-
end
-
-
12
items
-
end
-
-
# Maximum include depth is 10 in the API, but we raise it to 20 (by default),
-
# in case one of the included items has a reference in an upper level,
-
# so we can keep the include chain for that object as well
-
# Any included object after the maximum include resolution depth will be just a Link
-
1
def build_nested_resource(value, localized, includes)
-
2461
if @depth < @configuration.fetch(:max_include_resolution_depth, 20)
-
2330
resource = Support.resource_for_link(value, includes)
-
2330
return resolve_include(resource, localized, includes) unless resource.nil?
-
end
-
-
133
build_link(value)
-
end
-
-
1
def resolve_include(resource, localized, includes)
-
2328
require_relative 'resource_builder'
-
-
ResourceBuilder.new(
-
resource,
-
@configuration.merge(includes_for_single: includes),
-
localized,
-
@depth + 1,
-
includes
-
2328
).run
-
end
-
-
1
def known_link?(name)
-
88
field_name = name.to_sym
-
88
return true if known_contentful_object?(fields[field_name])
-
70
fields[field_name].is_a?(Enumerable) && known_contentful_object?(fields[field_name].first)
-
end
-
-
1
def known_contentful_object?(object)
-
105
(object.is_a?(Contentful::Entry) || object.is_a?(Contentful::Asset))
-
end
-
-
1
protected
-
-
1
def repr_name
-
"#{super}[#{sys[:content_type].id}]"
-
end
-
end
-
end
-
1
module Contentful
-
# All errors raised by the contentful gem are either instances of Contentful::Error
-
# or inherit from Contentful::Error
-
1
class Error < StandardError
-
1
attr_reader :response
-
-
1
def initialize(response)
-
21
@response = response
-
21
super @response.error_message
-
end
-
-
# Shortcut for creating specialized error classes
-
# USAGE rescue Contentful::Error[404]
-
1
def self.[](error_status_code)
-
22
case error_status_code
-
when 404
-
8
NotFound
-
when 400
-
3
BadRequest
-
when 403
-
1
AccessDenied
-
when 401
-
2
Unauthorized
-
when 429
-
2
RateLimitExceeded
-
when 500
-
1
ServerError
-
when 503
-
3
ServiceUnavailable
-
else
-
2
Error
-
end
-
end
-
end
-
-
# 404
-
1
class NotFound < Error; end
-
-
# 400
-
1
class BadRequest < Error; end
-
-
# 403
-
1
class AccessDenied < Error; end
-
-
# 401
-
1
class Unauthorized < Error; end
-
-
# 429
-
1
class RateLimitExceeded < Error; end
-
-
# 500
-
1
class ServerError < Error; end
-
-
# 503
-
1
class ServiceUnavailable < Error; end
-
-
# Raised when response is no valid json
-
1
class UnparsableJson < Error; end
-
-
# Raised when response is not parsable as a Contentful::Resource
-
1
class UnparsableResource < StandardError; end
-
end
-
1
require_relative 'location'
-
1
require_relative 'coercions'
-
-
1
module Contentful
-
# A ContentType's field schema
-
# See https://www.contentful.com/developers/documentation/content-management-api/#resources-content-types-fields
-
1
class Field
-
# Coercions from Contentful Types to Ruby native types
-
1
KNOWN_TYPES = {
-
'String' => StringCoercion,
-
'Text' => TextCoercion,
-
'Symbol' => SymbolCoercion,
-
'Integer' => IntegerCoercion,
-
'Float' => FloatCoercion,
-
'Boolean' => BooleanCoercion,
-
'Date' => DateCoercion,
-
'Location' => LocationCoercion,
-
'Object' => ObjectCoercion,
-
'Array' => ArrayCoercion,
-
'Link' => LinkCoercion
-
}
-
-
1
attr_reader :raw, :id, :name, :type, :link_type, :items, :required, :localized
-
-
1
def initialize(json)
-
522
@raw = json
-
522
@id = json.fetch('id', nil)
-
522
@name = json.fetch('name', nil)
-
522
@type = json.fetch('type', nil)
-
522
@link_type = json.fetch('linkType', nil)
-
522
@items = json.key?('items') ? Field.new(json.fetch('items', {})) : nil
-
522
@required = json.fetch('required', false)
-
522
@localized = json.fetch('localized', false)
-
end
-
-
# Coerces value to proper type
-
1
def coerce(value)
-
4551
return value if type.nil?
-
-
4551
options = {}
-
4551
options[:coercion_class] = KNOWN_TYPES[items.type] unless items.nil?
-
4551
KNOWN_TYPES[type].new(value, options).coerce
-
end
-
end
-
end
-
1
require_relative 'support'
-
1
require_relative 'base_resource'
-
-
1
module Contentful
-
# Base definition of a Contentful Resource containing Field properties
-
1
class FieldsResource < BaseResource
-
1
def initialize(item, _configuration, localized = false, includes = [], *)
-
2619
super
-
-
2619
@fields = hydrate_fields(localized, includes)
-
-
2619
define_fields_methods!
-
end
-
-
# Returns all fields of the asset
-
#
-
# @return [Hash] fields for Resource on selected locale
-
1
def fields(wanted_locale = nil)
-
5413
wanted_locale = internal_resource_locale if wanted_locale.nil?
-
5413
@fields.fetch(wanted_locale.to_s, {})
-
end
-
-
# Returns all fields of the asset with locales nested by field
-
#
-
# @return [Hash] fields for Resource grouped by field name
-
1
def fields_with_locales
-
5
remapped_fields = {}
-
5
locales.each do |locale|
-
8
fields(locale).each do |name, value|
-
38
remapped_fields[name] ||= {}
-
38
remapped_fields[name][locale.to_sym] = value
-
end
-
end
-
-
5
remapped_fields
-
end
-
-
# Provides a list of the available locales for a Resource
-
1
def locales
-
6
@fields.keys
-
end
-
-
# @private
-
1
def marshal_dump
-
15
raw_with_links
-
end
-
-
# @private
-
1
def marshal_load(raw_object)
-
22
super(raw_object)
-
44
localized = raw_object.fetch('fields', {}).all? { |_, v| v.is_a?(Hash) }
-
22
@fields = hydrate_fields(localized, [])
-
22
define_fields_methods!
-
end
-
-
# @private
-
1
def raw_with_links
-
103
links = fields.keys.select { |property| known_link?(property) }
-
15
processed_raw = raw.clone
-
15
raw['fields'].each do |k, v|
-
93
processed_raw['fields'][k] = links.include?(Support.snakify(k).to_sym) ? send(Support.snakify(k)) : v
-
end
-
-
15
processed_raw
-
end
-
-
1
private
-
-
1
def define_fields_methods!
-
2641
fields.each do |k, v|
-
11417
define_singleton_method k do
-
122
v
-
end
-
end
-
end
-
-
1
def hydrate_fields(localized, includes)
-
2641
return {} unless raw.key?('fields')
-
-
2634
locale = internal_resource_locale
-
2634
result = { locale => {} }
-
-
2634
if localized
-
1534
raw['fields'].each do |name, locales|
-
6573
locales.each do |loc, value|
-
7251
result[loc] ||= {}
-
7251
result[loc][Support.snakify(name).to_sym] = coerce(
-
Support.snakify(name),
-
value,
-
localized,
-
includes
-
)
-
end
-
end
-
else
-
1100
raw['fields'].each do |name, value|
-
4859
result[locale][Support.snakify(name).to_sym] = coerce(
-
Support.snakify(name),
-
value,
-
localized,
-
includes
-
)
-
end
-
end
-
-
2634
result
-
end
-
-
1
protected
-
-
1
def coerce(_field_id, value, _localized, _includes)
-
5109
value
-
end
-
end
-
end
-
1
module Contentful
-
# An Assets's file info
-
1
class File
-
1
attr_reader :file_name, :content_type, :details, :url
-
1
def initialize(json)
-
1259
@file_name = json.fetch('fileName', nil)
-
1259
@content_type = json.fetch('contentType', nil)
-
1259
@details = json.fetch('details', nil)
-
1259
@url = json.fetch('url', nil)
-
end
-
end
-
end
-
1
require_relative 'base_resource'
-
-
1
module Contentful
-
# Resource Class for Links
-
# https://www.contentful.com/developers/documentation/content-delivery-api/#links
-
1
class Link < BaseResource
-
# Queries contentful for the Resource the Link is refering to
-
# Takes an optional query hash
-
1
def resolve(client, query = {})
-
2
id_and_query = [(id unless link_type == 'Space')].compact + [query]
-
2
client.public_send(
-
Contentful::Support.snakify(link_type).to_sym,
-
*id_and_query
-
)
-
end
-
end
-
end
-
1
module Contentful
-
# A Locale definition as included in Space
-
# Read more about Localization at https://www.contentful.com/developers/documentation/content-delivery-api/#i18n
-
1
class Locale
-
1
attr_reader :code, :name, :default
-
-
1
def initialize(json)
-
18
@code = json.fetch('code', nil)
-
18
@name = json.fetch('name', nil)
-
18
@default = json.fetch('default', false)
-
end
-
end
-
end
-
1
module Contentful
-
# Location Field Type
-
# You can directly query for them: https://www.contentful.com/developers/documentation/content-delivery-api/#search-filter-geo
-
1
class Location
-
1
attr_reader :lat, :lon
-
1
alias latitude lat
-
1
alias longitude lon
-
-
1
def initialize(json)
-
2
@lat = json.fetch('lat', nil)
-
2
@lon = json.fetch('lon', nil)
-
end
-
end
-
end
-
1
module Contentful
-
# This object represents a request that is to be made. It gets initialized by the client
-
# with domain specific logic. The client later uses the Request's #url and #query methods
-
# to execute the HTTP request.
-
1
class Request
-
1
attr_reader :client, :type, :query, :id, :endpoint
-
-
1
def initialize(client, endpoint, query = {}, id = nil)
-
188
@client = client
-
188
@endpoint = endpoint
-
-
188
@query = (normalize_query(query) if query && !query.empty?)
-
-
188
if id
-
57
@type = :single
-
57
@id = URI.escape(id)
-
else
-
131
@type = :multi
-
131
@id = nil
-
end
-
end
-
-
# Returns the final URL, relative to a contentful space
-
1
def url
-
181
"#{@endpoint}#{@type == :single ? "/#{id}" : ''}"
-
end
-
-
# Delegates the actual HTTP work to the client
-
1
def get
-
168
client.get(self)
-
end
-
-
# Returns true if endpoint is an absolute url
-
1
def absolute?
-
176
@endpoint.start_with?('http')
-
end
-
-
# Returns a new Request object with the same data
-
1
def copy
-
Marshal.load(Marshal.dump(self))
-
end
-
-
1
private
-
-
1
def normalize_query(query)
-
86
Hash[
-
query.map do |key, value|
-
[
-
112
key.to_sym,
-
value.is_a?(::Array) ? value.join(',') : value
-
]
-
end
-
]
-
end
-
end
-
end
-
1
require_relative 'error'
-
1
require_relative 'space'
-
1
require_relative 'content_type'
-
1
require_relative 'entry'
-
1
require_relative 'asset'
-
1
require_relative 'array'
-
1
require_relative 'link'
-
1
require_relative 'deleted_entry'
-
1
require_relative 'deleted_asset'
-
-
1
module Contentful
-
# Transforms a Contentful::Response into a Contentful::Resource or a Contentful::Error
-
# See example/resource_mapping.rb for advanced usage
-
1
class ResourceBuilder
-
# Default Resource Mapping
-
# @see _ README for more information on Resource Mapping
-
1
DEFAULT_RESOURCE_MAPPING = {
-
'Space' => Space,
-
'ContentType' => ContentType,
-
'Entry' => Entry,
-
'Asset' => Asset,
-
'Array' => Array,
-
'Link' => Link,
-
'DeletedEntry' => DeletedEntry,
-
'DeletedAsset' => DeletedAsset
-
}
-
# Default Entry Mapping
-
# @see _ README for more information on Entry Mapping
-
1
DEFAULT_ENTRY_MAPPING = {}
-
-
1
attr_reader :json, :default_locale, :endpoint, :depth, :localized, :resource_mapping, :entry_mapping, :resource
-
-
1
def initialize(json, configuration = {}, localized = false, depth = 0, endpoint = nil)
-
2493
@json = json
-
2493
@default_locale = configuration.fetch(:default_locale, ::Contentful::Client::DEFAULT_CONFIGURATION[:default_locale])
-
2493
@resource_mapping = default_resource_mapping.merge(configuration.fetch(:resource_mapping, {}))
-
2493
@entry_mapping = default_entry_mapping.merge(configuration.fetch(:entry_mapping, {}))
-
2493
@includes_for_single = configuration.fetch(:includes_for_single, [])
-
2493
@localized = localized
-
2493
@depth = depth
-
2493
@endpoint = endpoint
-
2493
@configuration = configuration
-
end
-
-
# Starts the parsing process.
-
#
-
# @return [Contentful::Resource, Contentful::Error]
-
1
def run
-
2493
return build_array if array?
-
2384
build_single
-
rescue UnparsableResource => error
-
error
-
end
-
-
1
private
-
-
1
def build_array
-
109
includes = fetch_includes
-
109
result = json['items'].map do |item|
-
363
build_item(item, includes)
-
end
-
109
array_class = fetch_array_class
-
109
array_class.new(json.dup.merge('items' => result), default_locale, endpoint)
-
end
-
-
1
def build_single
-
2384
includes = @includes_for_single
-
2384
build_item(json, includes)
-
end
-
-
1
def build_item(item, includes = [])
-
2747
buildables = %w(Entry Asset ContentType Space DeletedEntry DeletedAsset)
-
7116
item_type = buildables.detect { |b| b.to_s == item['sys']['type'] }
-
2747
fail UnparsableResource, 'Item type is not known, could not parse' if item_type.nil?
-
2747
item_class = resource_class(item)
-
-
2747
item_class.new(item, @configuration, localized?, includes, depth)
-
end
-
-
1
def fetch_includes
-
109
includes = json['items'].dup
-
109
%w(Entry Asset).each do |type|
-
218
if json.fetch('includes', {}).key?(type)
-
62
includes.concat(json['includes'].fetch(type, []))
-
end
-
end
-
109
includes
-
end
-
-
1
def resource_class(item)
-
2747
return fetch_custom_resource_class(item) if %w(Entry Asset).include?(item['sys']['type'])
-
128
resource_mapping[item['sys']['type']]
-
end
-
-
1
def fetch_custom_resource_class(item)
-
2619
case item['sys']['type']
-
when 'Entry'
-
1362
resource_class = entry_mapping[item['sys']['contentType']['sys']['id']]
-
1362
return resource_class unless resource_class.nil?
-
-
1341
return fetch_custom_resource_mapping(item, 'Entry', Entry)
-
when 'Asset'
-
1257
return fetch_custom_resource_mapping(item, 'Asset', Asset)
-
end
-
end
-
-
1
def fetch_custom_resource_mapping(item, type, default_class)
-
2598
resources = resource_mapping[type]
-
2598
return default_class if resources.nil?
-
-
2598
return resources if resources.is_a?(Class)
-
return resources[item] if resources.respond_to?(:call)
-
-
default_class
-
end
-
-
1
def fetch_array_class
-
109
return SyncPage if sync?
-
68
::Contentful::Array
-
end
-
-
1
def localized?
-
2747
return true if @localized
-
1423
return true if array? && sync?
-
1178
false
-
end
-
-
1
def array?
-
3916
json.fetch('sys', {}).fetch('type', '') == 'Array'
-
end
-
-
1
def sync?
-
468
json.fetch('nextSyncUrl', nil) || json.fetch('nextPageUrl', nil)
-
end
-
-
# The default mapping for #detect_resource_class
-
1
def default_resource_mapping
-
2493
DEFAULT_RESOURCE_MAPPING.dup
-
end
-
-
# The default entry mapping
-
1
def default_entry_mapping
-
2493
DEFAULT_ENTRY_MAPPING.dup
-
end
-
end
-
end
-
1
require_relative 'base_resource'
-
1
require_relative 'locale'
-
-
1
module Contentful
-
# Resource class for Space.
-
# https://www.contentful.com/developers/documentation/content-delivery-api/#spaces
-
1
class Space < BaseResource
-
1
attr_reader :name, :locales
-
-
1
def initialize(item, *)
-
9
super
-
-
9
@name = item.fetch('name', nil)
-
27
@locales = item.fetch('locales', []).map { |locale| Locale.new(locale) }
-
end
-
-
# @private
-
1
def reload(client = nil)
-
return client.space unless client.nil?
-
-
false
-
end
-
end
-
end
-
1
module Contentful
-
# Utility methods used by the contentful gem
-
1
module Support
-
1
class << self
-
# Transforms CamelCase into snake_case (taken from zucker)
-
#
-
# @param [String] object camelCaseName
-
#
-
# @return [String] snake_case_name
-
1
def snakify(object)
-
String(object)
-
.gsub(/::/, '/')
-
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
-
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
-
.tr('-', '_')
-
87466
.downcase
-
end
-
-
# Returns true if resource is localized
-
#
-
# @return [true, false]
-
1
def localized?(value)
-
return false unless value.is_a? ::Hash
-
value.keys.any? { |possible_locale| Contentful::Constants::KNOWN_LOCALES.include?(possible_locale) }
-
end
-
-
# Checks if value is a link
-
#
-
# @param value
-
#
-
# @return [true, false]
-
1
def link?(value)
-
value.is_a?(::Hash) &&
-
10813
value.fetch('sys', {}).fetch('type', '') == 'Link'
-
end
-
-
# Checks if value is an array of links
-
#
-
# @param value
-
#
-
# @return [true, false]
-
1
def link_array?(value)
-
7125
return link?(value[0]) if value.is_a?(::Array) && !value.empty?
-
-
5875
false
-
end
-
-
# Returns the resource that matches the link
-
#
-
# @param [Hash] link
-
# @param [::Array] includes
-
#
-
# @return [Hash]
-
1
def resource_for_link(link, includes)
-
2330
includes.detect do |i|
-
i['sys']['id'] == link['sys']['id'] &&
-
16010
i['sys']['type'] == link['sys']['linkType']
-
end
-
end
-
end
-
end
-
end
-
1
require_relative 'resource_builder'
-
1
require_relative 'deleted_entry'
-
1
require_relative 'deleted_asset'
-
1
require_relative 'sync_page'
-
-
1
module Contentful
-
# Resource class for Sync.
-
# @see _ https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/synchronization
-
1
class Sync
-
1
attr_reader :next_sync_url
-
-
1
def initialize(client, options_or_url)
-
40
@client = client
-
40
@next_sync_url = nil
-
40
@first_page_options_or_url = options_or_url
-
end
-
-
# Iterates over all pages of the current sync
-
#
-
# @note Please Keep in Mind: Iterating fires a new request for each page
-
#
-
# @yield [Contentful::SyncPage]
-
1
def each_page
-
2
page = first_page
-
2
yield page if block_given?
-
-
2
until completed?
-
2
page = page.next_page
-
2
yield page if block_given?
-
end
-
end
-
-
# Returns the first sync result page
-
#
-
# @return [Contentful::SyncPage]
-
1
def first_page
-
28
get(@first_page_options_or_url)
-
end
-
-
# Returns false as long as last sync page has not been reached
-
#
-
# @return [Boolean]
-
1
def completed?
-
# rubocop:disable Style/DoubleNegation
-
4
!!next_sync_url
-
# rubocop:enable Style/DoubleNegation
-
end
-
-
# Directly iterates over all resources that have changed
-
#
-
# @yield [Contentful::Entry, Contentful::Asset]
-
1
def each_item(&block)
-
1
each_page do |page|
-
2
page.each_item(&block)
-
end
-
end
-
-
# @private
-
1
def get(options_or_url)
-
44
page = fetch_page(options_or_url)
-
-
44
return page if @client.configuration[:raw_mode]
-
-
41
link_page_to_sync! page
-
41
update_sync_state_from! page
-
-
41
page
-
end
-
-
1
private
-
-
1
def fetch_page(options_or_url)
-
44
return Request.new(@client, options_or_url).get if options_or_url.is_a? String
-
27
Request.new(@client, '/sync', options_or_url).get
-
end
-
-
1
def link_page_to_sync!(page)
-
41
page.instance_variable_set :@sync, self
-
end
-
-
1
def update_sync_state_from!(page)
-
41
@next_sync_url = page.next_sync_url
-
end
-
end
-
end
-
1
require_relative 'base_resource'
-
1
require_relative 'array_like'
-
-
1
module Contentful
-
# Wrapper Class for Sync results
-
1
class SyncPage < BaseResource
-
1
include Contentful::ArrayLike
-
-
1
attr_reader :sync, :items, :next_sync_url, :next_page_url
-
-
1
def initialize(item, default_locale, *)
-
41
super(item, { default_locale: default_locale }, true)
-
-
41
@items = item.fetch('items', [])
-
41
@next_sync_url = item.fetch('nextSyncUrl', nil)
-
41
@next_page_url = item.fetch('nextPageUrl', nil)
-
end
-
-
# @private
-
1
def inspect
-
"<#{repr_name} next_sync_url='#{next_sync_url}' last_page=#{last_page?}>"
-
end
-
-
# Requests next sync page from API
-
#
-
# @return [Contentful::SyncPage, void]
-
1
def next_page
-
5
sync.get(next_page_url) if next_page?
-
end
-
-
# Returns wether there is a next sync page
-
#
-
# @return [Boolean]
-
1
def next_page?
-
# rubocop:disable Style/DoubleNegation
-
7
!!next_page_url
-
# rubocop:enable Style/DoubleNegation
-
end
-
-
# Returns wether it is the last sync page
-
#
-
# @return [Boolean]
-
1
def last_page?
-
2
!next_page_url
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Asset do
-
31
let(:asset) { vcr('asset') { create_client.asset('nyancat') } }
-
-
1
describe 'SystemProperties' do
-
1
it 'has a #sys getter returning a hash with symbol keys' do
-
1
expect(asset.sys).to be_a Hash
-
1
expect(asset.sys.keys.sample).to be_a Symbol
-
end
-
-
1
it 'has #id' do
-
1
expect(asset.id).to eq 'nyancat'
-
end
-
-
1
it 'has #type' do
-
1
expect(asset.type).to eq 'Asset'
-
end
-
-
1
it 'has #space' do
-
1
expect(asset.space).to be_a Contentful::Link
-
end
-
-
1
it 'has #created_at' do
-
1
expect(asset.created_at).to be_a DateTime
-
end
-
-
1
it 'has #updated_at' do
-
1
expect(asset.updated_at).to be_a DateTime
-
end
-
-
1
it 'has #revision' do
-
1
expect(asset.revision).to eq 1
-
end
-
end
-
-
1
describe 'Fields' do
-
1
it 'has #title' do
-
1
expect(asset.title).to eq 'Nyan Cat'
-
end
-
-
1
it 'could have #description' do
-
1
expect(asset).to respond_to :description
-
end
-
-
1
it 'has #file' do
-
1
expect(asset.file).to be_a Contentful::File
-
end
-
end
-
-
1
describe '#image_url' do
-
1
it 'returns #url of #file without parameter' do
-
1
expect(asset.image_url).to eq asset.file.url
-
end
-
-
1
it 'adds image options if given' do
-
1
url = asset.image_url(width: 100, format: 'jpg', quality: 50, focus: 'top_right', fit: 'thumb', fl: 'progressive')
-
1
expect(url).to include asset.file.url
-
1
expect(url).to include '?w=100&fm=jpg&q=50&f=top_right&fit=thumb&fl=progressive'
-
end
-
end
-
-
1
describe '#url' do
-
1
it 'returns #url of #file without parameter' do
-
1
expect(asset.url).to eq asset.file.url
-
end
-
-
1
it 'adds image options if given' do
-
1
url = asset.url(width: 100, format: 'jpg', quality: 50, focus: 'top_right', fit: 'thumb', fl: 'progressive')
-
1
expect(url).to include asset.file.url
-
1
expect(url).to include '?w=100&fm=jpg&q=50&f=top_right&fit=thumb&fl=progressive'
-
end
-
end
-
-
1
it 'can be marshalled' do
-
1
marshalled = Marshal.dump(asset)
-
1
unmarshalled = Marshal.load(marshalled)
-
-
1
expect(unmarshalled.title).to eq 'Nyan Cat'
-
1
expect(unmarshalled.file).to be_a Contentful::File
-
end
-
-
1
describe 'select operator' do
-
5
let(:client) { create_client }
-
-
1
context 'with sys sent' do
-
1
it 'properly creates an entry' do
-
1
vcr('asset/select_only_sys') {
-
1
asset = client.assets(select: ['sys']).first
-
1
expect(asset.fields).to be_empty
-
1
expect(asset.sys).not_to be_empty
-
}
-
end
-
-
1
it 'can contain only one field' do
-
1
vcr('asset/select_one_field') {
-
1
asset = client.assets(select: ['sys', 'fields.file']).first
-
1
expect(asset.fields.keys).to eq([:file])
-
}
-
end
-
end
-
-
1
context 'without sys sent' do
-
1
it 'will enforce sys anyway' do
-
1
vcr('asset/select_no_sys') {
-
1
asset = client.assets(select: ['fields'], 'sys.id' => 'nyancat').first
-
-
1
expect(asset.id).to eq 'nyancat'
-
1
expect(asset.sys).not_to be_empty
-
}
-
end
-
-
1
it 'works with empty array as well, as sys is enforced' do
-
1
vcr('asset/select_empty_array') {
-
1
asset = client.assets(select: [], 'sys.id' => 'nyancat').first
-
-
1
expect(asset.id).to eq 'nyancat'
-
1
expect(asset.sys).not_to be_empty
-
}
-
end
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe 'Auto-include resources' do
-
3
let(:entries) { vcr('entries') { create_client.entries } } # entries come with asset includes
-
-
1
it 'replaces Contentful::Links which are actually included with the resource' do
-
1
asset = entries.items[1].fields[:image]
-
-
1
expect(asset).not_to be_a Contentful::Link
-
1
expect(asset).to be_a Contentful::Asset
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Client do
-
1
describe '#get' do
-
8
let(:client) { create_client }
-
2
let(:proxy_client) { create_client(proxy_host: '183.207.232.194',
-
proxy_port: 8080,
-
secure: false) }
-
9
let(:request) { Contentful::Request.new(nil, '/content_types', nil, 'cat') }
-
-
1
it 'uses #base_url' do
-
1
expect(client).to receive(:base_url).and_call_original
-
-
1
vcr('content_type') {
-
1
client.get(request)
-
}
-
end
-
-
1
it 'uses #request_headers' do
-
1
expect(client).to receive(:request_headers).and_call_original
-
2
vcr('content_type') { client.get(request) }
-
end
-
-
1
it 'uses Request#url' do
-
1
expect(request).to receive(:url).and_call_original
-
2
vcr('content_type') { client.get(request) }
-
end
-
-
1
it 'uses Request#query' do
-
1
expect(request).to receive(:query).twice.and_call_original
-
2
vcr('content_type') { client.get(request) }
-
end
-
-
1
it 'calls #get_http' do
-
2
expect(client.class).to receive(:get_http).with(client.base_url + request.url, request.query, client.request_headers, client.proxy_params) { raw_fixture('content_type') }
-
1
client.get(request)
-
end
-
-
1
it 'calls #get_http via proxy' do
-
2
expect(proxy_client.class).to receive(:get_http).with(proxy_client.base_url + request.url, request.query, proxy_client.request_headers, proxy_client.proxy_params) { raw_fixture('content_type') }
-
1
proxy_client.get(request)
-
1
expect(proxy_client.proxy_params[:host]).to eq '183.207.232.194'
-
1
expect(proxy_client.proxy_params[:port]).to eq 8080
-
end
-
-
1
describe 'build_resources parameter' do
-
1
it 'returns Contentful::Resource object if second parameter is true [default]' do
-
2
res = vcr('content_type') { client.get(request) }
-
1
expect(res).to be_a Contentful::BaseResource
-
end
-
-
1
it 'returns a Contentful::Response object if second parameter is not true' do
-
2
res = vcr('content_type') { client.get(request, false) }
-
1
expect(res).to be_a Contentful::Response
-
end
-
end
-
-
end
-
-
1
describe '#sync' do
-
1
it 'creates a new Sync object' do
-
1
expect(create_client.sync).to be_a Contentful::Sync
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::ContentType do
-
15
let(:content_type) { vcr('content_type') { create_client.content_type 'cat' } }
-
-
1
describe 'SystemProperties' do
-
1
it 'has a #sys getter returning a hash with symbol keys' do
-
1
expect(content_type.sys).to be_a Hash
-
1
expect(content_type.sys.keys.sample).to be_a Symbol
-
end
-
-
1
it 'has #id' do
-
1
expect(content_type.id).to eq 'cat'
-
end
-
-
1
it 'has #type' do
-
1
expect(content_type.type).to eq 'ContentType'
-
end
-
end
-
-
1
describe 'Properties' do
-
1
it 'has #name' do
-
1
expect(content_type.name).to eq 'Cat'
-
end
-
-
1
it 'has #description' do
-
1
expect(content_type.description).to eq 'Meow.'
-
end
-
-
1
it 'has #fields' do
-
1
expect(content_type.fields).to be_a Array
-
1
expect(content_type.fields.first).to be_a Contentful::Field
-
end
-
-
1
it 'could have #display_field' do
-
1
expect(content_type).to respond_to :display_field
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe 'DeletedAsset' do
-
1
let(:deleted_asset)do
-
4
vcr('sync_deleted_asset')do
-
4
create_client.sync(initial: true, type: 'DeletedAsset').first_page.items[0]
-
end
-
end
-
-
1
describe 'SystemProperties' do
-
1
it 'has a #sys getter returning a hash with symbol keys' do
-
1
expect(deleted_asset.sys).to be_a Hash
-
1
expect(deleted_asset.sys.keys.sample).to be_a Symbol
-
end
-
-
1
it 'has #id' do
-
1
expect(deleted_asset.id).to eq '5c6VY0gWg0gwaIeYkUUiqG'
-
end
-
-
1
it 'has #type' do
-
1
expect(deleted_asset.type).to eq 'DeletedAsset'
-
end
-
-
1
it 'has #deleted_at' do
-
1
expect(deleted_asset.created_at).to be_a DateTime
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe 'DeletedEntry' do
-
1
let(:deleted_entry)do
-
4
vcr('sync_deleted_entry')do
-
4
create_client.sync(initial: true, type: 'DeletedEntry').first_page.items[0]
-
end
-
end
-
-
1
describe 'SystemProperties' do
-
1
it 'has a #sys getter returning a hash with symbol keys' do
-
1
expect(deleted_entry.sys).to be_a Hash
-
1
expect(deleted_entry.sys.keys.sample).to be_a Symbol
-
end
-
-
1
it 'has #id' do
-
1
expect(deleted_entry.id).to eq 'CVebBDcQsSsu6yKKIayy'
-
end
-
-
1
it 'has #type' do
-
1
expect(deleted_entry.type).to eq 'DeletedEntry'
-
end
-
-
1
it 'has #deleted_at' do
-
1
expect(deleted_entry.created_at).to be_a DateTime
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Entry do
-
21
let(:entry) { vcr('entry') { create_client.entry 'nyancat' } }
-
-
1
describe 'SystemProperties' do
-
1
it 'has a #sys getter returning a hash with symbol keys' do
-
1
expect(entry.sys).to be_a Hash
-
1
expect(entry.sys.keys.sample).to be_a Symbol
-
end
-
-
1
it 'has #id' do
-
1
expect(entry.id).to eq 'nyancat'
-
end
-
-
1
it 'has #type' do
-
1
expect(entry.type).to eq 'Entry'
-
end
-
-
1
it 'has #space' do
-
1
expect(entry.space).to be_a Contentful::Link
-
end
-
-
1
it 'has #content_type' do
-
1
expect(entry.content_type).to be_a Contentful::Link
-
end
-
-
1
it 'has #created_at' do
-
1
expect(entry.created_at).to be_a DateTime
-
end
-
-
1
it 'has #updated_at' do
-
1
expect(entry.updated_at).to be_a DateTime
-
end
-
-
1
it 'has #revision' do
-
1
expect(entry.revision).to eq 5
-
end
-
end
-
-
1
describe 'Fields' do
-
1
it 'has a #fields getter returning a hash with symbol keys' do
-
1
expect(entry.sys).to be_a Hash
-
1
expect(entry.sys.keys.sample).to be_a Symbol
-
end
-
-
1
it "contains the entry's fields" do
-
1
expect(entry.fields[:color]).to eq 'rainbow'
-
1
expect(entry.fields[:best_friend]).to be_a Contentful::Entry
-
end
-
end
-
-
1
describe 'multiple locales' do
-
1
it 'can handle multiple locales' do
-
1
vcr('entry_locales') {
-
1
nyancat = create_client.entries(locale: "*", 'sys.id' => 'nyancat').items.first
-
1
expect(nyancat.fields('en-US')[:name]).to eq "Nyan Cat"
-
1
expect(nyancat.fields('tlh')[:name]).to eq "Nyan vIghro'"
-
-
-
1
expect(nyancat.fields(:'en-US')[:name]).to eq "Nyan Cat"
-
1
expect(nyancat.fields(:tlh)[:name]).to eq "Nyan vIghro'"
-
}
-
end
-
-
1
describe '#fields_with_locales' do
-
1
it 'can handle entries with just 1 locale' do
-
1
vcr('entry') {
-
1
nyancat = create_client.entry('nyancat')
-
1
expect(nyancat.fields_with_locales[:name].size).to eq(1)
-
1
expect(nyancat.fields_with_locales[:name][:'en-US']).to eq("Nyan Cat")
-
}
-
end
-
-
1
it 'can handle entries with multiple locales' do
-
1
vcr('entry_locales') {
-
1
nyancat = create_client.entries(locale: "*", 'sys.id' => 'nyancat').items.first
-
1
expect(nyancat.fields_with_locales[:name].size).to eq(2)
-
1
expect(nyancat.fields_with_locales[:name][:'en-US']).to eq("Nyan Cat")
-
1
expect(nyancat.fields_with_locales[:name][:tlh]).to eq("Nyan vIghro'")
-
}
-
end
-
-
1
it 'can have references in multiple locales and they are properly solved' do
-
1
vcr('multi_locale_reference') {
-
1
client = create_client(
-
space: '1sjfpsn7l90g',
-
access_token: 'e451a3cdfced9000220be41ed9c899866e8d52aa430eaf7c35b09df8fc6326f9',
-
dynamic_entries: :auto
-
)
-
-
1
entry = client.entries(locale: '*').first
-
-
1
expect(entry.image).to be_a ::Contentful::Asset
-
1
expect(entry.fields('zh')[:image]).to be_a ::Contentful::Asset
-
1
expect(entry.fields('es')[:image]).to be_a ::Contentful::Asset
-
-
1
expect(entry.image.id).not_to eq entry.fields('zh')[:image].id
-
}
-
end
-
-
1
it 'can have references with arrays in multiple locales and have them properly solved' do
-
1
vcr('multi_locale_array_reference') {
-
1
client = create_client(
-
space: 'cma9f9g4dxvs',
-
access_token: '3e4560614990c9ac47343b9eea762bdaaebd845766f619660d7230787fd545e1',
-
dynamic_entries: :auto
-
)
-
-
1
entry = client.entries(content_type: 'test', locale: '*').first
-
-
1
expect(entry.files).to be_a ::Array
-
1
expect(entry.references).to be_a ::Array
-
1
expect(entry.files.first).to be_a ::Contentful::Asset
-
1
expect(entry.references.first.entry?).to be_truthy
-
-
1
expect(entry.fields('zh')[:files]).to be_a ::Array
-
1
expect(entry.fields('zh')[:references]).to be_a ::Array
-
1
expect(entry.fields('zh')[:files].first).to be_a ::Contentful::Asset
-
1
expect(entry.fields('zh')[:references].first.entry?).to be_truthy
-
-
1
expect(entry.files.first.id).not_to eq entry.fields('zh')[:files].first.id
-
}
-
end
-
end
-
end
-
-
1
it '#raw' do
-
1
vcr('entry/raw') {
-
1
nyancat = create_client.entry('nyancat')
-
1
expect(nyancat.raw).to eq(create_client(raw_mode: true).entry('nyancat').object['items'].first)
-
}
-
end
-
-
1
describe 'can be marshalled' do
-
1
def test_dump(nyancat)
-
2
dump = Marshal.dump(nyancat)
-
2
new_cat = Marshal.load(dump)
-
-
# Attributes
-
2
expect(new_cat).to be_a Contentful::Entry
-
2
expect(new_cat.name).to eq "Nyan Cat"
-
2
expect(new_cat.lives).to eq 1337
-
-
# Single linked objects
-
2
expect(new_cat.best_friend).to be_a Contentful::Entry
-
2
expect(new_cat.best_friend.name).to eq "Happy Cat"
-
-
# Array of linked objects
-
2
expect(new_cat.cat_pack.count).to eq 2
-
2
expect(new_cat.cat_pack[0].name).to eq "Happy Cat"
-
2
expect(new_cat.cat_pack[1].name).to eq "Worried Cat"
-
-
# Nested Links
-
2
expect(new_cat.best_friend.best_friend).to be_a Contentful::Entry
-
2
expect(new_cat.best_friend.best_friend.name).to eq "Nyan Cat"
-
-
# Asset
-
2
expect(new_cat.image.file.url).to eq "//images.contentful.com/cfexampleapi/4gp6taAwW4CmSgumq2ekUm/9da0cd1936871b8d72343e895a00d611/Nyan_cat_250px_frame.png"
-
end
-
-
1
it 'marshals properly' do
-
1
vcr('entry/marshall') {
-
1
nyancat = create_client(gzip_encoded: false, max_include_resolution_depth: 2).entries(include: 2, 'sys.id' => 'nyancat').first
-
1
test_dump(nyancat)
-
}
-
end
-
-
1
it 'can remarshall an unmarshalled object' do
-
1
vcr('entry/marshall') {
-
1
nyancat = create_client(max_include_resolution_depth: 2).entries(include: 2, 'sys.id' => 'nyancat').first
-
-
# The double load/dump is on purpose
-
1
test_dump(Marshal.load(Marshal.dump(nyancat)))
-
}
-
end
-
end
-
-
1
describe 'select operator' do
-
6
let(:client) { create_client }
-
-
1
context 'with sys sent' do
-
1
it 'properly creates an entry' do
-
1
vcr('entry/select_only_sys') {
-
1
entry = client.entries(select: ['sys'], 'sys.id' => 'nyancat').first
-
1
expect(entry.fields).to be_empty
-
1
expect(entry.entry?).to be_truthy
-
}
-
end
-
-
1
describe 'can contain only one field' do
-
1
context 'with content_type sent' do
-
1
it 'will properly create the entry with one field' do
-
1
vcr('entry/select_one_field_proper') {
-
1
entry = client.entries(content_type: 'cat', select: ['sys', 'fields.name'], 'sys.id' => 'nyancat').first
-
1
expect(entry.fields).not_to be_empty
-
1
expect(entry.entry?).to be_truthy
-
1
expect(entry.fields[:name]).to eq 'Nyan Cat'
-
1
expect(entry.fields).to eq({name: 'Nyan Cat'})
-
}
-
end
-
end
-
-
1
context 'without content_type sent' do
-
1
it 'will raise an error' do
-
1
vcr('entry/select_one_field') {
-
2
expect { client.entries(select: ['sys', 'fields.name'], 'sys.id' => 'nyancat') }.to raise_error Contentful::BadRequest
-
}
-
end
-
end
-
end
-
end
-
-
1
context 'without sys sent' do
-
1
it 'will enforce sys anyway' do
-
1
vcr('entry/select_no_sys') {
-
1
entry = client.entries(select: ['fields'], 'sys.id' => 'nyancat').first
-
-
1
expect(entry.id).to eq 'nyancat'
-
1
expect(entry.sys).not_to be_empty
-
}
-
end
-
-
1
it 'works with empty array as well, as sys is enforced' do
-
1
vcr('entry/select_empty_array') {
-
1
entry = client.entries(select: [], 'sys.id' => 'nyancat').first
-
-
1
expect(entry.id).to eq 'nyancat'
-
1
expect(entry.sys).not_to be_empty
-
}
-
end
-
end
-
end
-
-
1
describe 'include resolution' do
-
1
it 'defaults to 20 depth' do
-
1
vcr('entry/include_resolution') {
-
1
entry = create_client.entry('nyancat', include: 2)
-
-
1
expect(entry.best_friend.name).to eq 'Happy Cat'
-
1
expect(entry
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend.name).to eq 'Nyan Cat'
-
-
1
expect(entry
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend.best_friend
-
.best_friend).to be_a ::Contentful::Link
-
}
-
end
-
-
1
it 'can be configured arbitrarily' do
-
1
vcr('entry/include_resolution') {
-
1
entry = create_client(max_include_resolution_depth: 3).entry('nyancat', include: 2)
-
-
1
expect(entry.best_friend.name).to eq 'Happy Cat'
-
1
expect(entry
-
.best_friend.best_friend
-
.best_friend.name).to eq 'Happy Cat'
-
1
expect(entry
-
.best_friend.best_friend
-
.best_friend.best_friend).to be_a ::Contentful::Link
-
}
-
end
-
end
-
-
1
describe 'issues' do
-
1
it 'Symbol/Text field with null values should be serialized as nil - #117' do
-
1
vcr('entries/issue_117') {
-
1
client = create_client(space: '8jbbayggj9gj', access_token: '4ce0108f04e55c76476ba84ab0e6149734db73d67cd1b429323ef67f00977e07')
-
1
entry = client.entries.first
-
-
1
expect(entry.nil).to be_nil
-
1
expect(entry.nil).not_to eq ''
-
}
-
end
-
-
1
describe 'JSON Fields should not be treated as locale data - #96' do
-
1
before do
-
2
vcr('entry/json_objects_client') {
-
2
@client = create_client(
-
space: 'h425t6gef30p',
-
access_token: '278f7aa72f2eb90c0e002d60f85bf2144c925acd2d37dd990d3ca274f25076cf',
-
dynamic_entries: :auto
-
)
-
-
}
-
2
vcr('entry/json_objects') {
-
2
@entry = @client.entries.first
-
}
-
end
-
-
1
it 'only has default locale' do
-
1
expect(@entry.locales).to eq ['en-US']
-
end
-
-
1
it 'can obtain all values properly' do
-
1
expect(@entry.name).to eq('Test')
-
1
expect(@entry.object_test).to eq({
-
null: nil,
-
text: 'some text',
-
array: [1, 2, 3],
-
number: 123,
-
boolean: true,
-
object: {
-
null: nil,
-
text: 'bar',
-
array: [1, 2, 3],
-
number: 123,
-
boolean: false,
-
object: {foo: 'bar'}
-
}
-
})
-
end
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Error do
-
3
let(:r) { Contentful::Response.new raw_fixture('not_found', 404) }
-
-
1
describe '#response' do
-
1
it 'returns the response the error has been initialized with' do
-
1
expect(Contentful::Error.new(r).response).to be r
-
end
-
end
-
-
1
describe '#message' do
-
1
it 'returns the message found in the response json' do
-
1
expect(Contentful::Error.new(r).message).not_to be_nil
-
1
expect(Contentful::Error.new(r).message).to \
-
eq json_fixture('not_found')['message']
-
end
-
end
-
-
1
describe Contentful::UnparsableJson do
-
1
describe '#message' do
-
1
it 'returns the json parser\'s message' do
-
1
uj = Contentful::Response.new raw_fixture('unparsable')
-
1
expect(Contentful::UnparsableJson.new(uj).message).to \
-
include 'unexpected token'
-
end
-
end
-
end
-
-
1
describe '.[]' do
-
-
1
it 'returns BadRequest error class for 400' do
-
1
expect(Contentful::Error[400]).to eq Contentful::BadRequest
-
end
-
-
1
it 'returns Unauthorized error class for 401' do
-
1
expect(Contentful::Error[401]).to eq Contentful::Unauthorized
-
end
-
-
1
it 'returns AccessDenied error class for 403' do
-
1
expect(Contentful::Error[403]).to eq Contentful::AccessDenied
-
end
-
-
1
it 'returns NotFound error class for 404' do
-
1
expect(Contentful::Error[404]).to eq Contentful::NotFound
-
end
-
-
1
it 'returns ServerError error class for 500' do
-
1
expect(Contentful::Error[500]).to eq Contentful::ServerError
-
end
-
-
1
it 'returns ServiceUnavailable error class for 503' do
-
1
expect(Contentful::Error[503]).to eq Contentful::ServiceUnavailable
-
end
-
-
1
it 'returns generic error class for any other value' do
-
1
expect(Contentful::Error[nil]).to eq Contentful::Error
-
1
expect(Contentful::Error[200]).to eq Contentful::Error
-
end
-
end
-
-
end
-
1
require 'spec_helper'
-
-
1
class NonCachingClient < Contentful::Client
-
1
def request_headers
-
8
headers = super
-
8
headers['Cf-No-Cache'] = 'foobar'
-
8
headers
-
end
-
end
-
-
1
class RetryLoggerMock < Logger
-
1
attr_reader :retry_attempts
-
-
1
def initialize(*)
-
1
super
-
1
@retry_attempts = 0
-
end
-
-
1
def info(message)
-
5
super
-
5
@retry_attempts += 1 if message.include?('Contentful API Rate Limit Hit! Retrying')
-
end
-
end
-
-
1
describe 'Error Requests' do
-
1
it 'will return 404 (Unauthorized) if resource not found' do
-
1
expect_vcr('not found')do
-
1
create_client.content_type 'not found'
-
end.to raise_error(Contentful::NotFound)
-
end
-
-
1
it 'will return 400 (BadRequest) if invalid parameters have been passed' do
-
1
expect_vcr('bad request')do
-
1
create_client.entries(some: 'parameter')
-
end.to raise_error(Contentful::BadRequest)
-
end
-
-
1
it 'will return 403 (AccessDenied) if ...' do
-
1
skip
-
end
-
-
1
it 'will return 401 (Unauthorized) if wrong credentials are given' do
-
1
client = Contentful::Client.new(space: 'wrong', access_token: 'credentials')
-
-
1
expect_vcr('unauthorized'){
-
1
client.entry('nyancat')
-
}.to raise_error(Contentful::Unauthorized)
-
end
-
-
1
it 'will return 500 (ServerError) if ...' do
-
1
skip
-
end
-
-
1
it 'will return a 429 if the ratelimit is reached and is not set to retry' do
-
1
client = Contentful::Client.new(space: 'wrong', access_token: 'credentials', max_rate_limit_retries: 0)
-
1
expect_vcr('ratelimit') {
-
1
client.entry('nyancat')
-
}.to raise_error(Contentful::RateLimitExceeded)
-
end
-
-
1
it 'will retry on 429 by default' do
-
1
logger = RetryLoggerMock.new(STDOUT)
-
1
client = NonCachingClient.new(
-
api_url: 'cdnorigin.flinkly.com',
-
space: '164vhtp008kz',
-
access_token: '7699b6c6f6cee9b6abaa216c71fbcb3eee56cb6f082f57b5e21b2b50f86bdea0',
-
raise_errors: true,
-
logger: logger
-
)
-
-
1
vcr('ratelimit_retry') {
-
1
3.times {
-
3
client.assets
-
}
-
}
-
-
1
expect(logger.retry_attempts).to eq 1
-
end
-
-
1
it 'will return 503 (ServiceUnavailable) when the service is unavailable' do
-
1
client = Contentful::Client.new(space: 'wrong', access_token: 'credentials')
-
-
1
expect_vcr('unavailable'){
-
1
client.entry('nyancat')
-
}.to raise_error(Contentful::ServiceUnavailable)
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Field do
-
13
let(:field) { vcr('field') { create_client.content_type('cat').fields.first } }
-
3
let(:linkField) { vcr('linkField') {
-
18
create_client.content_type('cat').fields.select { |f| f.id == 'image' }.first
-
} }
-
3
let(:arrayField) { vcr('arrayField') {
-
Contentful::Client.new(
-
space: 'wl1z0pal05vy',
-
access_token: '9b76e1bbc29eb513611a66b9fc5fb7acd8d95e83b0f7d6bacfe7ec926c819806'
-
26
).content_type('2PqfXUJwE8qSYKuM0U6w8M').fields.select { |f| f.id == 'categories' }.first
-
} }
-
-
1
describe 'Properties' do
-
1
it 'has #id' do
-
1
expect(field.id).to eq 'name'
-
end
-
-
1
it 'has #name' do
-
1
expect(field.name).to eq 'Name'
-
end
-
-
1
it 'has #type' do
-
1
expect(field.type).to eq 'Text'
-
end
-
-
1
it 'could have #items' do
-
1
expect(field).to respond_to :items
-
end
-
-
1
it 'has #required' do
-
1
expect(field.required).to be_truthy
-
end
-
-
1
it 'has #localized' do
-
1
expect(field.required).to be_truthy
-
end
-
end
-
-
1
describe 'Link field properties' do
-
1
it 'has #type' do
-
1
expect(linkField.type).to eq 'Link'
-
end
-
-
1
it 'has #linkType' do
-
1
expect(linkField.link_type).to eq 'Asset'
-
end
-
end
-
-
1
describe 'Array field properties' do
-
1
it 'has #type' do
-
1
expect(arrayField.type).to eq 'Array'
-
end
-
-
1
it 'has #items' do
-
1
expect(arrayField.items.type).to eq 'Link'
-
1
expect(arrayField.items.link_type).to eq 'Entry'
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::File do
-
9
let(:file) { vcr('asset') { create_client.asset('nyancat').file } }
-
-
1
describe 'Properties' do
-
1
it 'has #file_name' do
-
1
expect(file.file_name).to eq 'Nyan_cat_250px_frame.png'
-
end
-
-
1
it 'has #content_type' do
-
1
expect(file.content_type).to eq 'image/png'
-
end
-
-
1
it 'has #url' do
-
1
expect(file.url).to eq '//images.contentful.com/cfexampleapi/4gp6taAwW4CmSgumq2ekUm/9da0cd1936871b8d72343e895a00d611/Nyan_cat_250px_frame.png'
-
end
-
-
1
it 'has #details' do
-
1
expect(file.details).to be_instance_of Hash
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Link do
-
3
let(:client) { create_client }
-
13
let(:entry) { vcr('entry') { create_client.entry('nyancat') } }
-
6
let(:link) { entry.space }
-
2
let(:content_type_link) { entry.content_type }
-
-
1
describe 'SystemProperties' do
-
1
it 'has a #sys getter returning a hash with symbol keys' do
-
1
expect(link.sys).to be_a Hash
-
1
expect(link.sys.keys.sample).to be_a Symbol
-
end
-
-
1
it 'has #id' do
-
1
expect(link.id).to eq 'cfexampleapi'
-
end
-
-
1
it 'has #type' do
-
1
expect(link.type).to eq 'Link'
-
end
-
-
1
it 'has #link_type' do
-
1
expect(link.link_type).to eq 'Space'
-
end
-
end
-
-
1
describe '#resolve' do
-
1
it 'queries the api for the resource' do
-
1
vcr('space')do
-
1
expect(link.resolve(client)).to be_a Contentful::Space
-
end
-
end
-
-
1
it 'queries the api for the resource (different link object)' do
-
1
vcr('content_type')do
-
1
expect(content_type_link.resolve(client)).to be_a Contentful::ContentType
-
end
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Locale do
-
7
let(:locale) { vcr('locale') { create_client.space.locales.first } }
-
-
1
describe 'Properties' do
-
1
it 'has #code' do
-
1
expect(locale.code).to eq 'en-US'
-
end
-
-
1
it 'has #name' do
-
1
expect(locale.name).to eq 'English'
-
end
-
-
1
it 'has #default' do
-
1
expect(locale.default).to eq true
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Location do
-
1
let(:location)do
-
2
vcr('location')do
-
Contentful::Client.new(
-
space: 'lzjz8hygvfgu',
-
access_token: '0c6ef483524b5e46b3bafda1bf355f38f5f40b4830f7599f790a410860c7c271',
-
dynamic_entries: :auto,
-
2
).entry('3f6fq5ylFCi4kIYAQKsAYG').location
-
end
-
end
-
-
1
describe 'Properties' do
-
1
it 'has #lat' do
-
1
expect(location.lat).to be_a Float
-
1
expect(location.lat.to_i).to eq 36
-
end
-
-
1
it 'has #lon' do
-
1
expect(location.lon).to be_a Float
-
1
expect(location.lon.to_i).to eq(-94)
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Request do
-
1
describe '#get' do
-
1
it 'calls client' do
-
1
client = create_client
-
1
request = Contentful::Request.new(client, '/content_types', nil, 'nyancat')
-
-
1
expect(client).to receive(:get).with(request)
-
-
1
request.get
-
end
-
end
-
-
1
describe '#query' do
-
1
it 'converts arrays given in query to comma strings' do
-
1
client = create_client
-
1
request = Contentful::Request.new(client, '/entries', 'fields.likes[in]' => %w(jake finn))
-
1
expect(request.query[:'fields.likes[in]']).to eq 'jake,finn'
-
end
-
end
-
-
1
context '[single resource]' do
-
1
let(:request)do
-
2
Contentful::Request.new(create_client, '/content_types', nil, 'nyancat')
-
end
-
-
1
describe '#url' do
-
1
it 'contais endpoint' do
-
1
expect(request.url).to include 'content_types'
-
end
-
-
1
it 'contains id' do
-
1
expect(request.url).to include 'nyancat'
-
end
-
end
-
end
-
-
1
context '[multi resource]' do
-
1
let(:request)do
-
2
Contentful::Request.new(create_client, '/content_types', 'something' => 'requested')
-
end
-
-
1
describe '#query' do
-
1
it 'contains query' do
-
1
expect(request.query).not_to be_empty
-
1
expect(request.query[:something]).to eq 'requested'
-
end
-
end
-
-
1
describe '#url' do
-
1
it 'contais endpoint' do
-
1
expect(request.url).to include 'content_types'
-
end
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe 'Resource Building Examples' do
-
1
it 'can deal with arrays' do
-
1
request = Contentful::Request.new(nil, 'entries')
-
1
response = Contentful::Response.new(raw_fixture('link_array'), request)
-
1
resource = Contentful::ResourceBuilder.new(response.object).run
-
-
1
expect(resource.fields[:links]).to be_a Array
-
1
expect(resource.fields[:links].first).to be_a Contentful::Link
-
end
-
-
1
it 'replaces links with included versions if present' do
-
1
request = Contentful::Request.new(nil, 'entries')
-
1
response = Contentful::Response.new(raw_fixture('includes'), request)
-
1
resource = Contentful::ResourceBuilder.new(response.object).run.first
-
-
1
expect(resource.fields[:links]).to be_a Array
-
1
expect(resource.fields[:links].first).to be_a Contentful::Entry
-
end
-
-
1
it 'can also reference itself' do
-
1
request = Contentful::Request.new(nil, 'entries')
-
1
response = Contentful::Response.new(raw_fixture('self_link'), request)
-
1
resource = Contentful::ResourceBuilder.new(response.object).run.first
-
-
1
other_resource = resource.fields[:e]
-
1
expect(other_resource).to be_a Contentful::Entry
-
1
expect(other_resource.fields[:e]).to eq resource
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Response do
-
5
let(:successful_response) { Contentful::Response.new raw_fixture('nyancat'), Contentful::Request.new(nil, '/entries', nil, 'nyancat') }
-
3
let(:error_response) { Contentful::Response.new raw_fixture('not_found', 404) }
-
3
let(:unparsable_response) { Contentful::Response.new raw_fixture('unparsable') }
-
-
1
describe '#raw' do
-
1
it 'returns the raw response it has been initalized with' do
-
1
expect(successful_response.raw.to_s).to eql raw_fixture('nyancat').to_s
-
end
-
end
-
-
1
describe '#object' do
-
1
it "returns the repsonse's parsed json" do
-
1
expect(successful_response.object).to eq json_fixture('nyancat')
-
end
-
end
-
-
1
describe '#request' do
-
1
it 'returns the request the response has been initalized with' do
-
1
expect(successful_response.request).to be_a Contentful::Request
-
end
-
end
-
-
1
describe '#status' do
-
1
it 'returns :ok for normal responses' do
-
1
expect(successful_response.status).to eq :ok
-
end
-
-
1
it 'returns :error for error responses' do
-
1
expect(error_response.status).to eq :error
-
end
-
-
1
it 'returns :error for unparsable json responses' do
-
1
expect(unparsable_response.status).to eq :error
-
end
-
-
1
it 'returns :error for responses without content' do
-
1
raw_response = ''
-
3
allow(raw_response).to receive(:status) { 204 }
-
1
no_content_response = Contentful::Response.new raw_response
-
1
expect(no_content_response.status).to eq :no_content
-
end
-
end
-
-
1
describe '#error_message' do
-
1
it 'returns contentful error message for contentful errors' do
-
1
expect(error_response.error_message).to eq 'The resource could not be found.'
-
end
-
-
1
it 'returns json parser error message for json parse errors' do
-
1
expect(unparsable_response.error_message).to include 'unexpected token'
-
end
-
-
1
it 'returns a ServiceUnavailable error on a 503' do
-
1
error_response = Contentful::Response.new raw_fixture('not_found', 503)
-
1
expect(error_response.status).to eql :error
-
1
expect(error_response.object).to be_kind_of Contentful::ServiceUnavailable
-
end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Space do
-
11
let(:space) { vcr('space') { create_client.space } }
-
-
1
describe 'SystemProperties' do
-
1
it 'has a #sys getter returning a hash with symbol keys' do
-
1
expect(space.sys).to be_a Hash
-
1
expect(space.sys.keys.sample).to be_a Symbol
-
end
-
-
1
it 'has #id' do
-
1
expect(space.id).to eq 'cfexampleapi'
-
end
-
-
1
it 'has #type' do
-
1
expect(space.type).to eq 'Space'
-
end
-
end
-
-
1
describe 'Properties' do
-
1
it 'has #name' do
-
1
expect(space.name).to eq 'Contentful Example API'
-
end
-
-
1
it 'has #locales' do
-
1
expect(space.locales).to be_a Array
-
1
expect(space.locales.first).to be_a Contentful::Locale
-
end
-
end
-
end
-
1
def create_client(options = {})
-
171
Contentful::Client.new({
-
space: 'cfexampleapi',
-
access_token: 'b4c0n73n7fu1',
-
}.merge(options))
-
end
-
1
require 'multi_json'
-
-
1
def raw_fixture(which, status = 200, _as_json = false)
-
18
object = Object.new
-
46
allow(object).to receive(:status) { status }
-
34
allow(object).to receive(:headers) { {} }
-
41
allow(object).to receive(:to_s) { File.read File.dirname(__FILE__) + "/../fixtures/json_responses/#{which}.json" }
-
-
18
object
-
end
-
-
1
def json_fixture(which, _as_json = false)
-
2
MultiJson.load(
-
File.read File.dirname(__FILE__) + "/../fixtures/json_responses/#{which}.json"
-
)
-
end
-
1
require 'vcr'
-
-
1
VCR.configure do |c|
-
1
c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
-
1
c.ignore_localhost = true
-
1
c.hook_into :webmock
-
1
c.default_cassette_options = { record: :once }
-
end
-
-
1
def vcr(name, &block)
-
159
VCR.use_cassette(name, &block)
-
end
-
-
1
def expect_vcr(name, &block)
-
14
expect { VCR.use_cassette(name, &block) }
-
end
-
1
require 'spec_helper'
-
-
1
describe Contentful::Sync do
-
1
before :each do
-
13
Contentful::ContentTypeCache.clear!
-
end
-
-
1
let(:first_page) do
-
2
vcr('sync_page')do
-
2
create_client.sync(initial: true).first_page
-
end
-
end
-
-
1
let(:last_page) do
-
2
vcr('sync_page')do
-
2
vcr('sync_page_2')do
-
2
create_client.sync(initial: true).first_page.next_page
-
end
-
end
-
end
-
-
1
describe '#initialize' do
-
1
it 'takes an options hash on initialization' do
-
1
expect do
-
2
vcr('sync_deletion') { create_client.sync(initial: true, type: 'Deletion').first_page }
-
end.not_to raise_exception
-
end
-
-
1
it 'takes a next_sync_url on initialization' do
-
1
expect do
-
2
vcr('sync_page_2') { create_client.sync('https://cdn.contentful.com/spaces/cfexampleapi/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdybCr8Okw6AYwqbDksO3ehvDpUPCgcKsKXbCiAwPC8K2w4LDvsOkw6nCjhPDpcOQADElWsOoU8KGR3HCtsOAwqd6wp_Dulp8w6LDsF_CtsK7Kk05wrMvwrLClMOgG2_Dn2sGPg').first_page }
-
end.not_to raise_exception
-
end
-
end
-
-
1
describe '#first_page' do
-
1
it 'returns only the first page of a new sync' do
-
1
vcr('sync_page')do
-
1
expect(create_client.sync(initial: true).first_page).to be_a Contentful::SyncPage
-
end
-
end
-
end
-
-
1
describe '#each_page' do
-
1
it 'iterates through sync pages' do
-
1
sync = create_client.sync(initial: true)
-
2
vcr('sync_page'){ vcr('sync_page_2'){
-
1
count = 0
-
1
sync.each_page do |page|
-
2
expect(page).to be_a Contentful::SyncPage
-
2
count += 1
-
end
-
1
expect(count).to eq 2
-
}}
-
end
-
end
-
-
1
describe '#next_sync_url' do
-
1
it 'is empty if there are still more pages to request in the current sync' do
-
1
expect(first_page.next_sync_url).to be_nil
-
end
-
-
1
it 'returns the url to continue the sync next time' do
-
1
expect(last_page.next_sync_url).to be_a String
-
end
-
end
-
-
1
describe '#completed?' do
-
1
it 'will return true if no more pages to request in the current sync' do
-
1
expect(first_page.next_sync_url).to be_falsey
-
end
-
-
1
it 'will return true if not all pages requested, yet' do
-
1
expect(last_page.next_sync_url).to be_truthy
-
end
-
end
-
-
1
describe '#each_item' do
-
1
it 'will directly iterate through all resources' do
-
1
sync = create_client.sync(initial: true)
-
2
vcr('sync_page'){ vcr('sync_page_2'){
-
1
sync.each_item do |item|
-
14
expect(item).to be_a Contentful::BaseResource
-
end
-
}}
-
end
-
end
-
-
1
describe 'Resource parsing' do
-
1
it 'will correctly parse the `file` field of an asset' do
-
1
sync = create_client.sync(initial: true)
-
1
vcr('sync_page') {
-
15
asset = sync.first_page.items.select { |item| item.is_a?(Contentful::Asset) }.first
-
-
1
expect(asset.file.file_name).to eq 'doge.jpg'
-
1
expect(asset.file.content_type).to eq 'image/jpeg'
-
1
expect(asset.file.details['image']['width']).to eq 5800
-
1
expect(asset.file.details['image']['height']).to eq 4350
-
1
expect(asset.file.details['size']).to eq 522943
-
1
expect(asset.file.url).to eq '//images.contentful.com/cfexampleapi/1x0xpXu4pSGS4OukSyWGUK/cc1239c6385428ef26f4180190532818/doge.jpg'
-
}
-
end
-
end
-
-
1
describe 'raw_mode' do
-
1
before do
-
3
@sync = create_client(raw_mode: true).sync(initial: true)
-
end
-
-
1
it 'should not fail' do
-
1
vcr('sync_page_short') {
-
2
expect { @sync.first_page }.not_to raise_error
-
}
-
end
-
-
1
it 'should return a raw Response' do
-
1
vcr('sync_page_short') {
-
1
expect(@sync.first_page).to be_a Contentful::Response
-
}
-
end
-
-
1
it 'should return JSON' do
-
1
expected = {
-
"sys" => {"type" => "Array"},
-
"items" => [
-
{
-
"sys" => {
-
"space" => {
-
"sys" => {
-
"type" => "Link",
-
"linkType" => "Space",
-
"id" => "cfexampleapi"}
-
},
-
"type" => "Entry",
-
"contentType" => {
-
"sys" => {
-
"type" => "Link",
-
"linkType" => "ContentType",
-
"id" => "1t9IbcfdCk6m04uISSsaIK"
-
}
-
},
-
"id" => "5ETMRzkl9KM4omyMwKAOki",
-
"revision" => 2,
-
"createdAt" => "2014-02-21T13:42:57.752Z",
-
"updatedAt" => "2014-04-16T12:44:02.691Z"
-
},
-
"fields" => {
-
"name" => {"en-US"=>"London"},
-
"center" => {
-
"en-US" => {"lat"=>51.508515, "lon"=>-0.12548719999995228}
-
}
-
}
-
}
-
],
-
"nextSyncUrl" => "https://cdn.contentful.com/spaces/cfexampleapi/sync?sync_token=w5ZGw6JFwqZmVcKsE8Kow4grw45QdybCr8Okw6AYwqbDksO3ehvDpUPCgcKsKXbCiAwPC8K2w4LDvsOkw6nCjhPDpcOQADElWsOoU8KGR3HCtsOAwqd6wp_Dulp8w6LDsF_CtsK7Kk05wrMvwrLClMOgG2_Dn2sGPg"
-
}
-
1
vcr('sync_page_short') {
-
1
expect(@sync.first_page.object).to eql expected
-
}
-
end
-
end
-
end