wcc-contentful 0.3.0 → 1.0.0.pre.rc2
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.
- checksums.yaml +5 -5
- data/.rspec +1 -1
- data/Guardfile +43 -0
- data/README.md +161 -11
- data/Rakefile +3 -6
- data/app/controllers/wcc/contentful/webhook_controller.rb +25 -24
- data/app/jobs/wcc/contentful/webhook_enable_job.rb +36 -2
- data/bin/console +4 -3
- data/bin/rails +2 -0
- data/config/routes.rb +1 -1
- data/doc +1 -0
- data/lib/tasks/download_schema.rake +12 -0
- data/lib/wcc/contentful.rb +69 -45
- data/lib/wcc/contentful/active_record_shim.rb +72 -0
- data/lib/wcc/contentful/configuration.rb +177 -46
- data/lib/wcc/contentful/content_type_indexer.rb +14 -0
- data/lib/wcc/contentful/downloads_schema.rb +112 -0
- data/lib/wcc/contentful/engine.rb +33 -14
- data/lib/wcc/contentful/event.rb +171 -0
- data/lib/wcc/contentful/events.rb +41 -0
- data/lib/wcc/contentful/exceptions.rb +3 -33
- data/lib/wcc/contentful/indexed_representation.rb +2 -2
- data/lib/wcc/contentful/instrumentation.rb +31 -0
- data/lib/wcc/contentful/link.rb +28 -0
- data/lib/wcc/contentful/link_visitor.rb +122 -0
- data/lib/wcc/contentful/middleware.rb +7 -0
- data/lib/wcc/contentful/middleware/store.rb +158 -0
- data/lib/wcc/contentful/middleware/store/caching_middleware.rb +114 -0
- data/lib/wcc/contentful/model.rb +37 -4
- data/lib/wcc/contentful/model_builder.rb +1 -0
- data/lib/wcc/contentful/model_methods.rb +40 -15
- data/lib/wcc/contentful/model_singleton_methods.rb +47 -30
- data/lib/wcc/contentful/rake.rb +4 -0
- data/lib/wcc/contentful/rspec.rb +46 -0
- data/lib/wcc/contentful/services.rb +61 -27
- data/lib/wcc/contentful/simple_client.rb +81 -25
- data/lib/wcc/contentful/simple_client/management.rb +43 -10
- data/lib/wcc/contentful/simple_client/response.rb +61 -22
- data/lib/wcc/contentful/simple_client/typhoeus_adapter.rb +17 -17
- data/lib/wcc/contentful/store.rb +7 -66
- data/lib/wcc/contentful/store/README.md +85 -0
- data/lib/wcc/contentful/store/base.rb +34 -119
- data/lib/wcc/contentful/store/cdn_adapter.rb +71 -12
- data/lib/wcc/contentful/store/factory.rb +186 -0
- data/lib/wcc/contentful/store/instrumentation.rb +55 -0
- data/lib/wcc/contentful/store/interface.rb +82 -0
- data/lib/wcc/contentful/store/memory_store.rb +27 -24
- data/lib/wcc/contentful/store/postgres_store.rb +268 -101
- data/lib/wcc/contentful/store/postgres_store/schema_1.sql +73 -0
- data/lib/wcc/contentful/store/postgres_store/schema_2.sql +21 -0
- data/lib/wcc/contentful/store/query.rb +246 -0
- data/lib/wcc/contentful/store/query/interface.rb +63 -0
- data/lib/wcc/contentful/store/rspec_examples.rb +48 -0
- data/lib/wcc/contentful/store/rspec_examples/basic_store.rb +629 -0
- data/lib/wcc/contentful/store/rspec_examples/include_param.rb +283 -0
- data/lib/wcc/contentful/store/rspec_examples/nested_queries.rb +342 -0
- data/lib/wcc/contentful/sync_engine.rb +181 -0
- data/lib/wcc/contentful/test.rb +7 -0
- data/lib/wcc/contentful/test/attributes.rb +56 -0
- data/lib/wcc/contentful/test/double.rb +76 -0
- data/lib/wcc/contentful/test/factory.rb +101 -0
- data/lib/wcc/contentful/version.rb +1 -1
- data/wcc-contentful.gemspec +28 -14
- metadata +248 -152
- data/.circleci/config.yml +0 -51
- data/.gitignore +0 -26
- data/.rubocop.yml +0 -242
- data/.rubocop_todo.yml +0 -19
- data/.travis.yml +0 -5
- data/CHANGELOG.md +0 -180
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -8
- data/LICENSE.txt +0 -21
- data/app/jobs/wcc/contentful/delayed_sync_job.rb +0 -63
- data/lib/generators/wcc/USAGE +0 -24
- data/lib/generators/wcc/model_generator.rb +0 -90
- data/lib/generators/wcc/templates/.keep +0 -0
- data/lib/generators/wcc/templates/Procfile +0 -3
- data/lib/generators/wcc/templates/contentful_shell_wrapper +0 -385
- data/lib/generators/wcc/templates/menu/generated_add_menus.ts +0 -192
- data/lib/generators/wcc/templates/menu/models/menu.rb +0 -23
- data/lib/generators/wcc/templates/menu/models/menu_button.rb +0 -23
- data/lib/generators/wcc/templates/page/generated_add_pages.ts +0 -50
- data/lib/generators/wcc/templates/page/models/page.rb +0 -23
- data/lib/generators/wcc/templates/release +0 -9
- data/lib/generators/wcc/templates/wcc_contentful.rb +0 -17
- data/lib/wcc/contentful/client_ext.rb +0 -28
- data/lib/wcc/contentful/graphql.rb +0 -14
- data/lib/wcc/contentful/graphql/builder.rb +0 -177
- data/lib/wcc/contentful/graphql/types.rb +0 -54
- data/lib/wcc/contentful/model/dropdown_menu.rb +0 -7
- data/lib/wcc/contentful/model/menu.rb +0 -6
- data/lib/wcc/contentful/model/menu_button.rb +0 -16
- data/lib/wcc/contentful/model/page.rb +0 -8
- data/lib/wcc/contentful/model/redirect.rb +0 -19
- data/lib/wcc/contentful/model_validators.rb +0 -121
- data/lib/wcc/contentful/model_validators/dsl.rb +0 -166
- data/lib/wcc/contentful/simple_client/http_adapter.rb +0 -24
- data/lib/wcc/contentful/store/lazy_cache_store.rb +0 -161
@@ -0,0 +1,181 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'wcc/contentful/event'
|
4
|
+
require 'wisper'
|
5
|
+
|
6
|
+
begin
|
7
|
+
gem 'activejob'
|
8
|
+
require 'active_job'
|
9
|
+
rescue Gem::LoadError # rubocop:disable Lint/HandleExceptions
|
10
|
+
# suppress
|
11
|
+
end
|
12
|
+
|
13
|
+
module WCC::Contentful
|
14
|
+
# The SyncEngine is used to keep the currently configured store up to date
|
15
|
+
# using the Sync API. It is available on the WCC::Contentful::Services instance,
|
16
|
+
# and the application is responsible to periodically call #next in order to hit
|
17
|
+
# the sync API and update the store.
|
18
|
+
#
|
19
|
+
# If you have mounted the WCC::Contentful::Engine, AND the configured store is
|
20
|
+
# one that can be synced (i.e. it responds to `:index`), then
|
21
|
+
# the WCC::Contentful::WebhookController will call #next automatically anytime
|
22
|
+
# a webhook is received. Otherwise you should hook up to the Webhook events
|
23
|
+
# and call the sync engine via your initializer:
|
24
|
+
# WCC::Contentful::Events.subscribe(proc do |event|
|
25
|
+
# WCC::Contentful::Services.instance.sync_engine.next(up_to: event.dig('sys', 'id'))
|
26
|
+
# end, with: :call)
|
27
|
+
class SyncEngine
|
28
|
+
include ::Wisper::Publisher
|
29
|
+
|
30
|
+
def state
|
31
|
+
(@state&.dup || token_wrapper_factory(nil)).freeze
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :store
|
35
|
+
attr_reader :client
|
36
|
+
|
37
|
+
def should_sync?
|
38
|
+
store&.index?
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(state: nil, store: nil, client: nil, key: nil)
|
42
|
+
@state_key = key || "sync:#{object_id}"
|
43
|
+
@client = client || WCC::Contentful::Services.instance.client
|
44
|
+
@mutex = Mutex.new
|
45
|
+
|
46
|
+
if store
|
47
|
+
unless %i[index index? find].all? { |m| store.respond_to?(m) }
|
48
|
+
raise ArgumentError, ':store param must implement the Store interface'
|
49
|
+
end
|
50
|
+
|
51
|
+
@store = store
|
52
|
+
@state = read_state if should_sync?
|
53
|
+
end
|
54
|
+
if state
|
55
|
+
@state = token_wrapper_factory(state)
|
56
|
+
raise ArgumentError, ':state param must be a String or Hash' unless @state.is_a? Hash
|
57
|
+
unless @state.dig('sys', 'type') == 'token'
|
58
|
+
raise ArgumentError, ':state param must be of sys.type = "token"'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
raise ArgumentError, 'either :state or :store must be provided' unless @state || @store
|
62
|
+
end
|
63
|
+
|
64
|
+
# Gets the next increment of data from the Sync API.
|
65
|
+
# If the configured store responds to `:index`, that will be called with each
|
66
|
+
# item in the Sync response to update the store.
|
67
|
+
# If a block is passed, that block will be evaluated with each item in the
|
68
|
+
# response.
|
69
|
+
# @param [String] up_to_id An ID to look for in the response. The method returns
|
70
|
+
# true if the ID was found or no up_to_id was given, false if the ID did not come back.
|
71
|
+
# @return [Array] A `[Boolean, Integer]` tuple where the first value is whether the ID was found,
|
72
|
+
# and the second value is the number of items returned.
|
73
|
+
def next(up_to_id: nil)
|
74
|
+
id_found = up_to_id.nil?
|
75
|
+
all_events = []
|
76
|
+
|
77
|
+
@mutex.synchronize do
|
78
|
+
@state ||= read_state || token_wrapper_factory(nil)
|
79
|
+
next_sync_token = @state['token']
|
80
|
+
|
81
|
+
sync_resp = client.sync(sync_token: next_sync_token)
|
82
|
+
sync_resp.items.each do |item|
|
83
|
+
id = item.dig('sys', 'id')
|
84
|
+
id_found ||= id == up_to_id
|
85
|
+
|
86
|
+
store.index(item) if store&.index?
|
87
|
+
event = WCC::Contentful::Event.from_raw(item, source: self)
|
88
|
+
yield(event) if block_given?
|
89
|
+
emit_event(event)
|
90
|
+
all_events << event
|
91
|
+
end
|
92
|
+
|
93
|
+
@state = @state.merge('token' => sync_resp.next_sync_token)
|
94
|
+
write_state
|
95
|
+
end
|
96
|
+
|
97
|
+
emit_sync_complete(all_events)
|
98
|
+
|
99
|
+
[id_found, all_events.length]
|
100
|
+
end
|
101
|
+
|
102
|
+
def emit_event(event)
|
103
|
+
type = event.dig('sys', 'type')
|
104
|
+
raise ArgumentError, "Unknown event type #{event}" unless type.present?
|
105
|
+
|
106
|
+
broadcast(type, event)
|
107
|
+
end
|
108
|
+
|
109
|
+
def emit_sync_complete(events)
|
110
|
+
event = WCC::Contentful::Event::SyncComplete.new(events, source: self)
|
111
|
+
broadcast('SyncComplete', event)
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def read_state
|
117
|
+
return unless found = store&.find(@state_key)
|
118
|
+
|
119
|
+
# backwards compat - migrate existing state
|
120
|
+
token_wrapper_factory(found)
|
121
|
+
end
|
122
|
+
|
123
|
+
def write_state
|
124
|
+
store.index(@state) if store&.index?
|
125
|
+
end
|
126
|
+
|
127
|
+
def token_wrapper_factory(state)
|
128
|
+
state = { 'token' => state } unless state.is_a? Hash
|
129
|
+
|
130
|
+
state.merge!('sys' => { 'id' => @state_key, 'type' => 'token' }) unless state['sys']
|
131
|
+
state
|
132
|
+
end
|
133
|
+
|
134
|
+
# Define the job only if rails is loaded
|
135
|
+
if defined?(ActiveJob)
|
136
|
+
# This job uses the Contentful Sync API to update the configured store with
|
137
|
+
# the latest data from Contentful.
|
138
|
+
class Job < ActiveJob::Base
|
139
|
+
include WCC::Contentful::ServiceAccessors
|
140
|
+
|
141
|
+
self.queue_adapter = :async
|
142
|
+
queue_as :default
|
143
|
+
|
144
|
+
def perform(event = nil)
|
145
|
+
return unless sync_engine&.should_sync?
|
146
|
+
|
147
|
+
up_to_id = nil
|
148
|
+
up_to_id = event[:up_to_id] || event.dig('sys', 'id') if event
|
149
|
+
sync!(up_to_id: up_to_id)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Calls the Contentful Sync API and updates the configured store with the returned
|
153
|
+
# data.
|
154
|
+
#
|
155
|
+
# @param [String] up_to_id
|
156
|
+
# An ID that we know has changed and should come back from the sync.
|
157
|
+
# If we don't find this ID in the sync data, then drop a job to try
|
158
|
+
# the sync again after a few minutes.
|
159
|
+
#
|
160
|
+
def sync!(up_to_id: nil)
|
161
|
+
id_found, count = sync_engine.next(up_to_id: up_to_id)
|
162
|
+
|
163
|
+
next_sync_token = sync_engine.state['token']
|
164
|
+
|
165
|
+
logger.info "Synced #{count} entries. Next sync token:\n #{next_sync_token}"
|
166
|
+
logger.info "Should enqueue again? [#{!id_found}]"
|
167
|
+
# Passing nil to only enqueue the job 1 more time
|
168
|
+
sync_later!(up_to_id: nil) unless id_found
|
169
|
+
next_sync_token
|
170
|
+
end
|
171
|
+
|
172
|
+
# Drops an ActiveJob job to invoke WCC::Contentful.sync! after a given amount
|
173
|
+
# of time.
|
174
|
+
def sync_later!(up_to_id: nil, wait: 10.minutes)
|
175
|
+
self.class.set(wait: wait)
|
176
|
+
.perform_later(up_to_id: up_to_id)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WCC::Contentful::Test::Attributes
|
4
|
+
DEFAULTS = {
|
5
|
+
String: 'test',
|
6
|
+
Int: 0,
|
7
|
+
Float: 0.0,
|
8
|
+
DateTime: Time.at(0).to_s,
|
9
|
+
Boolean: false,
|
10
|
+
Json: ->(_f) { {} },
|
11
|
+
Coordinates: ->(_f) { {} },
|
12
|
+
Asset: ->(f) {
|
13
|
+
WCC::Contentful::Link.new(
|
14
|
+
"fake-#{f.name}-#{SecureRandom.urlsafe_base64[1..6]}",
|
15
|
+
:Asset
|
16
|
+
).raw
|
17
|
+
},
|
18
|
+
Link: ->(f) {
|
19
|
+
WCC::Contentful::Link.new(
|
20
|
+
"fake-#{f.name}-#{SecureRandom.urlsafe_base64[1..6]}",
|
21
|
+
:Link
|
22
|
+
).raw
|
23
|
+
}
|
24
|
+
}.freeze
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def [](key)
|
28
|
+
DEFAULTS[key]
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Get a hash of default values for all attributes unique to the given Contentful model.
|
33
|
+
def defaults(const)
|
34
|
+
unless const < WCC::Contentful::Model
|
35
|
+
raise ArgumentError, "#{const} is not a subclass of WCC::Contentful::Model"
|
36
|
+
end
|
37
|
+
|
38
|
+
const.content_type_definition.fields.each_with_object({}) do |(name, f), h|
|
39
|
+
h[name.to_sym] = h[name.underscore.to_sym] = default_value(f)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Gets the default value for a contentful IndexedRepresentation::Field.
|
45
|
+
# This comes from the 'content_type_definition' of a contentful model class.
|
46
|
+
def default_value(field)
|
47
|
+
return [] if field.array
|
48
|
+
return unless field.required
|
49
|
+
|
50
|
+
val = DEFAULTS[field.type]
|
51
|
+
return val.call(field) if val.respond_to?(:call)
|
52
|
+
|
53
|
+
val
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './attributes'
|
4
|
+
|
5
|
+
module WCC::Contentful::Test::Double
|
6
|
+
##
|
7
|
+
# Builds a rspec double of the Contentful model for the given content_type.
|
8
|
+
# All attributes that are known to be required fields on the content type
|
9
|
+
# will return a default value based on the field type.
|
10
|
+
def contentful_double(content_type, **attrs)
|
11
|
+
const = WCC::Contentful::Model.resolve_constant(content_type)
|
12
|
+
attrs.symbolize_keys!
|
13
|
+
|
14
|
+
bad_attrs = attrs.reject { |a| const.instance_methods.include?(a) }
|
15
|
+
raise ArgumentError, "Attribute(s) do not exist on #{const}: #{bad_attrs.keys}" if bad_attrs.any?
|
16
|
+
|
17
|
+
double(attrs[:name] || attrs[:id] || nil, defaults(const).merge(attrs))
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Builds an rspec double of a Contentful image asset, including the file
|
22
|
+
# URL and details. These fields can be overridden.
|
23
|
+
def contentful_image_double(**attrs)
|
24
|
+
attrs = {
|
25
|
+
title: WCC::Contentful::Test::Attributes[:String],
|
26
|
+
description: WCC::Contentful::Test::Attributes[:String],
|
27
|
+
file: {
|
28
|
+
url: '//images.ctfassets.net/7yx6/2rak/test.jpg',
|
29
|
+
details: {
|
30
|
+
image: {
|
31
|
+
width: 0,
|
32
|
+
height: 0
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}.deep_merge!(attrs)
|
37
|
+
|
38
|
+
attrs[:file] = OpenStruct.new(attrs[:file]) if attrs[:file]
|
39
|
+
|
40
|
+
attrs[:raw] = {
|
41
|
+
sys: {
|
42
|
+
space: {
|
43
|
+
sys: {
|
44
|
+
type: 'Link',
|
45
|
+
linkType: 'Space',
|
46
|
+
id: ENV['CONTENTFUL_SPACE_ID']
|
47
|
+
}
|
48
|
+
},
|
49
|
+
id: SecureRandom.urlsafe_base64,
|
50
|
+
type: 'Asset',
|
51
|
+
createdAt: Time.now.to_s(:iso8601),
|
52
|
+
updatedAt: Time.now.to_s(:iso8601),
|
53
|
+
environment: {
|
54
|
+
sys: {
|
55
|
+
id: 'master',
|
56
|
+
type: 'Link',
|
57
|
+
linkType: 'Environment'
|
58
|
+
}
|
59
|
+
},
|
60
|
+
revision: rand(100),
|
61
|
+
locale: 'en-US'
|
62
|
+
},
|
63
|
+
fields: attrs.each_with_object({}) { |(k, v), h| h[k] = { 'en-US' => v } }
|
64
|
+
}
|
65
|
+
|
66
|
+
double(attrs)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def defaults(model)
|
72
|
+
attributes = WCC::Contentful::Test::Attributes.defaults(model)
|
73
|
+
methods = model.instance_methods - WCC::Contentful::Model.instance_methods
|
74
|
+
methods.each_with_object(attributes) { |f, h| h[f] ||= nil }
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './attributes'
|
4
|
+
|
5
|
+
module WCC::Contentful::Test::Factory
|
6
|
+
##
|
7
|
+
# Builds a in-memory instance of the Contentful model for the given content_type.
|
8
|
+
# All attributes that are known to be required fields on the content type
|
9
|
+
# will return a default value based on the field type.
|
10
|
+
def contentful_create(content_type, context = nil, **attrs)
|
11
|
+
const = WCC::Contentful::Model.resolve_constant(content_type.to_s)
|
12
|
+
attrs = attrs.transform_keys { |a| a.to_s.camelize(:lower) }
|
13
|
+
|
14
|
+
id = attrs.delete('id')
|
15
|
+
sys = attrs.delete('sys')
|
16
|
+
raw = attrs.delete('raw') || default_raw(const, id)
|
17
|
+
bad_attrs = attrs.reject { |a| const.content_type_definition.fields.key?(a) }
|
18
|
+
raise ArgumentError, "Attribute(s) do not exist on #{const}: #{bad_attrs.keys}" if bad_attrs.any?
|
19
|
+
|
20
|
+
raw['sys'].merge!(sys) if sys
|
21
|
+
|
22
|
+
attrs.each do |k, v|
|
23
|
+
field = const.content_type_definition.fields[k]
|
24
|
+
|
25
|
+
raw_value = v
|
26
|
+
raw_value = to_raw(v, field.type) if %i[Asset Link].include?(field.type)
|
27
|
+
raw['fields'][field.name][raw.dig('sys', 'locale')] = raw_value
|
28
|
+
end
|
29
|
+
|
30
|
+
instance = const.new(raw, context)
|
31
|
+
|
32
|
+
attrs.each do |k, v|
|
33
|
+
field = const.content_type_definition.fields[k]
|
34
|
+
next unless %i[Asset Link].include?(field.type)
|
35
|
+
|
36
|
+
unless field.array ? v.any? { |i| i.is_a?(String) } : v.is_a?(String)
|
37
|
+
instance.instance_variable_set("@#{field.name}_resolved", v)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
instance
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def default_instance(model, id = nil)
|
47
|
+
model.new(default_raw(model, id))
|
48
|
+
end
|
49
|
+
|
50
|
+
def default_raw(model, id = nil)
|
51
|
+
{ sys: contentful_sys(model, id), fields: contentful_fields(model) }.as_json
|
52
|
+
end
|
53
|
+
|
54
|
+
def contentful_sys(model, id = nil)
|
55
|
+
{
|
56
|
+
space: {
|
57
|
+
sys: {
|
58
|
+
type: 'Link',
|
59
|
+
linkType: 'Space',
|
60
|
+
id: ENV['CONTENTFUL_SPACE_ID']
|
61
|
+
}
|
62
|
+
},
|
63
|
+
id: id || SecureRandom.urlsafe_base64,
|
64
|
+
type: 'Entry',
|
65
|
+
createdAt: Time.now.to_s(:iso8601),
|
66
|
+
updatedAt: Time.now.to_s(:iso8601),
|
67
|
+
environment: {
|
68
|
+
sys: {
|
69
|
+
id: 'master',
|
70
|
+
type: 'Link',
|
71
|
+
linkType: 'Environment'
|
72
|
+
}
|
73
|
+
},
|
74
|
+
revision: rand(100),
|
75
|
+
contentType: {
|
76
|
+
sys: {
|
77
|
+
type: 'Link',
|
78
|
+
linkType: 'ContentType',
|
79
|
+
id: model.content_type
|
80
|
+
}
|
81
|
+
},
|
82
|
+
locale: 'en-US'
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
def contentful_fields(model)
|
87
|
+
WCC::Contentful::Test::Attributes.defaults(model).each_with_object({}) do |(k, v), h|
|
88
|
+
h[k] = { 'en-US' => v }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_raw(val, field_type)
|
93
|
+
if val.is_a? Array
|
94
|
+
val.map { |i| to_raw(i, field_type) }
|
95
|
+
elsif val.is_a? String
|
96
|
+
WCC::Contentful::Link.new(val, field_type).raw
|
97
|
+
elsif val
|
98
|
+
val.raw
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/wcc-contentful.gemspec
CHANGED
@@ -4,17 +4,24 @@ lib = File.expand_path('lib', __dir__)
|
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require 'wcc/contentful/version'
|
6
6
|
|
7
|
+
doc_version = Gem::Version.new(WCC::Contentful::VERSION).release.to_s.sub(/\.\d+$/, '')
|
8
|
+
|
9
|
+
# rubocop:disable Metrics/LineLength
|
7
10
|
Gem::Specification.new do |spec|
|
8
11
|
spec.name = 'wcc-contentful'
|
9
12
|
spec.version = WCC::Contentful::VERSION
|
10
13
|
spec.authors = ['Watermark Dev']
|
11
14
|
spec.email = ['dev@watermark.org']
|
12
15
|
|
13
|
-
spec.summary = File.readlines('README.md').join
|
14
|
-
spec.description = 'Contentful API wrapper library
|
15
|
-
spec.homepage = 'https://github.com/watermarkchurch/wcc-contentful'
|
16
|
+
spec.summary = File.readlines(File.expand_path('README.md', __dir__)).join
|
17
|
+
spec.description = 'Contentful API wrapper library exposing an ActiveRecord-like interface'
|
18
|
+
spec.homepage = 'https://github.com/watermarkchurch/wcc-contentful/wcc-contentful'
|
16
19
|
spec.license = 'MIT'
|
17
20
|
|
21
|
+
spec.metadata = {
|
22
|
+
'documentation_uri' => "https://watermarkchurch.github.io/wcc-contentful/#{doc_version}/wcc-contentful"
|
23
|
+
}
|
24
|
+
|
18
25
|
spec.required_ruby_version = '>= 2.3'
|
19
26
|
|
20
27
|
spec.files =
|
@@ -24,36 +31,43 @@ Gem::Specification.new do |spec|
|
|
24
31
|
|
25
32
|
spec.require_paths = ['lib']
|
26
33
|
|
34
|
+
spec.add_development_dependency 'byebug', '~> 11.0.1'
|
35
|
+
spec.add_development_dependency 'coveralls'
|
27
36
|
spec.add_development_dependency 'dotenv', '~> 2.2'
|
37
|
+
spec.add_development_dependency 'erb_lint', '~> 0.0.26'
|
28
38
|
spec.add_development_dependency 'httplog', '~> 1.0'
|
29
|
-
spec.add_development_dependency 'rake', '~>
|
39
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
30
40
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
31
|
-
spec.add_development_dependency '
|
32
|
-
spec.add_development_dependency '
|
33
|
-
spec.add_development_dependency '
|
41
|
+
spec.add_development_dependency 'rspec-instrumentation-matcher'
|
42
|
+
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4.1'
|
43
|
+
spec.add_development_dependency 'rubocop', '0.68'
|
44
|
+
spec.add_development_dependency 'simplecov', '~> 0.16.1'
|
45
|
+
spec.add_development_dependency 'vcr', '~> 5.0'
|
34
46
|
spec.add_development_dependency 'webmock', '~> 3.0'
|
47
|
+
spec.add_development_dependency 'wisper-rspec'
|
35
48
|
|
36
49
|
# Makes testing easy via `bundle exec guard`
|
37
50
|
spec.add_development_dependency 'guard', '~> 2.14'
|
38
51
|
spec.add_development_dependency 'guard-rspec', '~> 4.7'
|
39
52
|
spec.add_development_dependency 'guard-rubocop', '~> 1.3.0'
|
53
|
+
spec.add_development_dependency 'guard-shell', '~> 0.7.1'
|
40
54
|
|
41
55
|
# for generators
|
42
56
|
spec.add_development_dependency 'generator_spec', '~> 0.9.4'
|
43
|
-
spec.add_development_dependency 'rails', '~> 5.
|
44
|
-
spec.add_development_dependency 'rspec-rails', '~> 3.7'
|
45
|
-
spec.add_development_dependency 'sqlite3'
|
57
|
+
# spec.add_development_dependency 'rails', '~> 5.0'
|
58
|
+
# spec.add_development_dependency 'rspec-rails', '~> 3.7'
|
59
|
+
spec.add_development_dependency 'sqlite3', '~> 1.3.6'
|
46
60
|
spec.add_development_dependency 'timecop', '~> 0.9.1'
|
47
61
|
|
48
62
|
# optional dependencies
|
49
|
-
spec.add_development_dependency '
|
50
|
-
spec.add_development_dependency '
|
51
|
-
spec.add_development_dependency 'graphql', '~> 1.7'
|
63
|
+
spec.add_development_dependency 'connection_pool', '~> 2.2'
|
64
|
+
spec.add_development_dependency 'faraday', '~> 0.9'
|
52
65
|
spec.add_development_dependency 'http', '> 1.0', '< 3.0'
|
53
66
|
spec.add_development_dependency 'pg', '~> 1.0'
|
54
67
|
spec.add_development_dependency 'typhoeus', '~> 1.3'
|
55
68
|
|
56
69
|
spec.add_dependency 'activesupport', '>= 5'
|
57
|
-
spec.add_dependency 'dry-validation', '~> 0.11.1'
|
58
70
|
spec.add_dependency 'wcc-base', '~> 0.3.1'
|
71
|
+
spec.add_dependency 'wisper', '~> 2.0.0'
|
59
72
|
end
|
73
|
+
# rubocop:enable Metrics/LineLength
|