wcc-contentful 1.2.0 → 1.3.1
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 +4 -4
- data/README.md +25 -1
- data/app/controllers/wcc/contentful/webhook_controller.rb +2 -0
- data/lib/tasks/download_schema.rake +1 -1
- data/lib/wcc/contentful/configuration.rb +37 -18
- data/lib/wcc/contentful/downloads_schema.rb +5 -4
- data/lib/wcc/contentful/engine.rb +2 -4
- data/lib/wcc/contentful/event.rb +2 -3
- data/lib/wcc/contentful/exceptions.rb +2 -3
- data/lib/wcc/contentful/indexed_representation.rb +2 -6
- data/lib/wcc/contentful/instrumentation.rb +2 -1
- data/lib/wcc/contentful/link.rb +1 -3
- data/lib/wcc/contentful/link_visitor.rb +2 -4
- data/lib/wcc/contentful/middleware/store/caching_middleware.rb +4 -8
- data/lib/wcc/contentful/middleware/store.rb +4 -6
- data/lib/wcc/contentful/model_api.rb +3 -5
- data/lib/wcc/contentful/model_builder.rb +5 -4
- data/lib/wcc/contentful/model_methods.rb +10 -12
- data/lib/wcc/contentful/model_singleton_methods.rb +1 -1
- data/lib/wcc/contentful/rich_text/node.rb +1 -3
- data/lib/wcc/contentful/rich_text.rb +1 -1
- data/lib/wcc/contentful/rspec.rb +1 -3
- data/lib/wcc/contentful/services.rb +9 -0
- data/lib/wcc/contentful/simple_client/cdn.rb +126 -0
- data/lib/wcc/contentful/simple_client/preview.rb +17 -0
- data/lib/wcc/contentful/simple_client/response.rb +24 -19
- data/lib/wcc/contentful/simple_client.rb +13 -118
- data/lib/wcc/contentful/store/base.rb +19 -27
- data/lib/wcc/contentful/store/cdn_adapter.rb +1 -1
- data/lib/wcc/contentful/store/factory.rb +1 -1
- data/lib/wcc/contentful/store/memory_store.rb +10 -7
- data/lib/wcc/contentful/store/postgres_store.rb +52 -42
- data/lib/wcc/contentful/store/query.rb +2 -2
- data/lib/wcc/contentful/store/rspec_examples/include_param.rb +6 -4
- data/lib/wcc/contentful/store/rspec_examples/operators.rb +1 -1
- data/lib/wcc/contentful/sync_engine.rb +58 -34
- data/lib/wcc/contentful/sys.rb +2 -1
- data/lib/wcc/contentful/test/double.rb +3 -5
- data/lib/wcc/contentful/test/factory.rb +4 -6
- data/lib/wcc/contentful/version.rb +1 -1
- data/lib/wcc/contentful.rb +9 -12
- data/wcc-contentful.gemspec +5 -5
- metadata +37 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58a77a1fbe7e5a7f99d8f13142c29ccac39d7101dfbe2769f542d18e88634a40
|
4
|
+
data.tar.gz: 8a4748e01236daaf0f6bce2c32b2999e02205de77977b6fee01280ea84b83241
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 992a019411bac0fb5c14819db375ed2c8a318c94ccc78b46237598a0ece9aa3646c3b34315738e5c20b7583f43fd0fdec946594cc6e96d92fdaa1b084b425aae
|
7
|
+
data.tar.gz: 4ba8042ea71939b58d51239e4d8b325d6a714f051ff273c2cbcc4116f707eac3b0ca2b695cc73de2904bdcb9cd2f2651927c4987e4967cee514e4d5acd1e9511
|
data/README.md
CHANGED
@@ -565,7 +565,10 @@ to multiple spaces within the same ruby process! You just have to create and in
|
|
565
565
|
The {WCC::Contentful::ModelAPI} concern makes this straightforward. Start by creating your Namespace
|
566
566
|
and including the concern:
|
567
567
|
```ruby
|
568
|
-
#
|
568
|
+
# lib/my_second_space.rb
|
569
|
+
|
570
|
+
# Note: This class must be in the "lib" folder in :zeitwerk mode, otherwise Rails 6+ will unload all your constants
|
571
|
+
# that were created in the initializer. Your models which subclass this namespace may reside in the app/models directory.
|
569
572
|
class MySecondSpace
|
570
573
|
include WCC::Contentful::ModelAPI
|
571
574
|
end
|
@@ -587,6 +590,11 @@ MySecondSpace.configure do |config|
|
|
587
590
|
config.space = ENV['SECOND_CONTENTFUL_SPACE_ID']
|
588
591
|
config.environment = ENV['CONTENTFUL_ENVIRONMENT']
|
589
592
|
end
|
593
|
+
|
594
|
+
# Ensure that models are reloaded in Rails development mode
|
595
|
+
Rails.application.config.to_prepare do
|
596
|
+
MySecondSpace.reload!
|
597
|
+
end
|
590
598
|
```
|
591
599
|
|
592
600
|
Finally, use it:
|
@@ -614,6 +622,22 @@ sync_engine = MySecondSpace.services.sync_engine
|
|
614
622
|
Note that the above services are not accessible on {WCC::Contentful::Services.instance}
|
615
623
|
or via the {WCC::Contentful::ServiceAccessors}.
|
616
624
|
|
625
|
+
#### Important Note when using Zeitwerk with Rails 6+
|
626
|
+
When using Rails >= 6 with `config.autoloader = :zeitwerk`, Rails will remove any models defined in `app/models` after
|
627
|
+
initialization and then load them again when they are referenced. If you `include WCC::Contentful::ModelAPI` in a class
|
628
|
+
defined inside the `app` directory, this will have the effect of deleting all configuration that was set in the initializer
|
629
|
+
as well as the constants generated from your schema.
|
630
|
+
This will result in one of two errors:
|
631
|
+
|
632
|
+
* `NameError (uninitialized constant MySecondSpace::MyContentType)`
|
633
|
+
if you try to reference a subclass such as `MyContentType < MySecondSpace::MyContentType`
|
634
|
+
* `ArgumentError (Not yet configured!)`
|
635
|
+
if you try to `MySecondSpace.find('xxxx')` to load an Entry or Asset
|
636
|
+
|
637
|
+
The solution is to have your secondary namespace in a folder which is not in the `autoload_paths`.
|
638
|
+
We suggest using `lib`, which will work so long as you have not added the `lib` folder to the `autoload_paths` as some
|
639
|
+
uninformed StackOverflow answers suggest you do.
|
640
|
+
|
617
641
|
### Using a sync store with a second space
|
618
642
|
|
619
643
|
If you use something other than the CDNAdapter with your second space, you will
|
@@ -36,6 +36,7 @@ module WCC::Contentful
|
|
36
36
|
def authorize_contentful
|
37
37
|
config = WCC::Contentful.configuration
|
38
38
|
|
39
|
+
# rubocop:disable Style/SoleNestedConditional
|
39
40
|
if config.webhook_username.present? && config.webhook_password.present?
|
40
41
|
unless authenticate_with_http_basic do |u, p|
|
41
42
|
u == config.webhook_username &&
|
@@ -45,6 +46,7 @@ module WCC::Contentful
|
|
45
46
|
return
|
46
47
|
end
|
47
48
|
end
|
49
|
+
# rubocop:enable Style/SoleNestedConditional
|
48
50
|
|
49
51
|
# 'application/vnd.contentful.management.v1+json' is an alias for the 'application/json'
|
50
52
|
# content-type, so 'request.content_type' will give 'application/json'
|
@@ -5,7 +5,7 @@ require 'wcc/contentful/downloads_schema'
|
|
5
5
|
|
6
6
|
namespace :wcc_contentful do
|
7
7
|
desc 'Downloads the schema from the currently configured space and stores it in ' \
|
8
|
-
|
8
|
+
'db/contentful-schema.json'
|
9
9
|
task download_schema: :environment do
|
10
10
|
WCC::Contentful::DownloadsSchema.call
|
11
11
|
end
|
@@ -3,22 +3,25 @@
|
|
3
3
|
# This object contains all the configuration options for the `wcc-contentful` gem.
|
4
4
|
class WCC::Contentful::Configuration
|
5
5
|
ATTRIBUTES = %i[
|
6
|
-
space
|
7
6
|
access_token
|
8
7
|
app_url
|
9
|
-
management_token
|
10
|
-
environment
|
11
|
-
default_locale
|
12
|
-
preview_token
|
13
|
-
webhook_username
|
14
|
-
webhook_password
|
15
|
-
webhook_jobs
|
16
8
|
connection
|
17
9
|
connection_options
|
18
|
-
|
10
|
+
default_locale
|
11
|
+
environment
|
12
|
+
instrumentation_adapter
|
13
|
+
logger
|
14
|
+
management_token
|
15
|
+
preview_token
|
19
16
|
schema_file
|
17
|
+
space
|
20
18
|
store
|
21
|
-
|
19
|
+
sync_retry_limit
|
20
|
+
sync_retry_wait
|
21
|
+
update_schema_file
|
22
|
+
webhook_jobs
|
23
|
+
webhook_password
|
24
|
+
webhook_username
|
22
25
|
].freeze
|
23
26
|
|
24
27
|
# (required) Sets the Contentful Space ID.
|
@@ -57,6 +60,17 @@ class WCC::Contentful::Configuration
|
|
57
60
|
# to implement a webhook job.
|
58
61
|
attr_accessor :webhook_jobs
|
59
62
|
|
63
|
+
# Sets the maximum number of times that the SyncEngine will retry synchronization
|
64
|
+
# when it detects that the Contentful CDN's cache has not been updated after a webhook.
|
65
|
+
# Default: 2
|
66
|
+
attr_accessor :sync_retry_limit
|
67
|
+
|
68
|
+
# Sets the base ActiveSupport::Duration that the SyncEngine will wait before retrying.
|
69
|
+
# Each subsequent retry uses an exponential backoff, so the second retry will be
|
70
|
+
# after (2 * sync_retry_wait), the third after (4 * sync_retry_wait), etc.
|
71
|
+
# Default: 2.seconds
|
72
|
+
attr_accessor :sync_retry_wait
|
73
|
+
|
60
74
|
# Returns true if the currently configured environment is pointing at `master`.
|
61
75
|
def master?
|
62
76
|
!environment.present?
|
@@ -145,9 +159,7 @@ class WCC::Contentful::Configuration
|
|
145
159
|
# WCC::Contentful::InitializationError if the API cannot be reached.
|
146
160
|
def update_schema_file=(sym)
|
147
161
|
valid_syms = %i[never if_possible if_missing always]
|
148
|
-
unless valid_syms.include?(sym)
|
149
|
-
raise ArgumentError, "update_schema_file must be one of #{valid_syms}"
|
150
|
-
end
|
162
|
+
raise ArgumentError, "update_schema_file must be one of #{valid_syms}" unless valid_syms.include?(sym)
|
151
163
|
|
152
164
|
@update_schema_file = sym
|
153
165
|
end
|
@@ -171,23 +183,30 @@ class WCC::Contentful::Configuration
|
|
171
183
|
# to :instrument like ActiveSupport::Notifications.instrument
|
172
184
|
attr_accessor :instrumentation_adapter
|
173
185
|
|
186
|
+
# Sets the logger to be used by the wcc-contentful gem, including stores.
|
187
|
+
# Defaults to the rails logger if in a rails context, otherwise creates a new
|
188
|
+
# logger that writes to STDERR.
|
189
|
+
attr_accessor :logger
|
190
|
+
|
174
191
|
def initialize
|
175
|
-
@access_token = ENV
|
176
|
-
@app_url = ENV
|
192
|
+
@access_token = ENV.fetch('CONTENTFUL_ACCESS_TOKEN', nil)
|
193
|
+
@app_url = ENV.fetch('APP_URL', nil)
|
177
194
|
@connection_options = {
|
178
195
|
api_url: 'https://cdn.contentful.com/',
|
179
196
|
preview_api_url: 'https://preview.contentful.com/',
|
180
197
|
management_api_url: 'https://api.contentful.com'
|
181
198
|
}
|
182
|
-
@management_token = ENV
|
183
|
-
@preview_token = ENV
|
184
|
-
@space = ENV
|
199
|
+
@management_token = ENV.fetch('CONTENTFUL_MANAGEMENT_TOKEN', nil)
|
200
|
+
@preview_token = ENV.fetch('CONTENTFUL_PREVIEW_TOKEN', nil)
|
201
|
+
@space = ENV.fetch('CONTENTFUL_SPACE_ID', nil)
|
185
202
|
@default_locale = nil
|
186
203
|
@middleware = []
|
187
204
|
@update_schema_file = :if_possible
|
188
205
|
@schema_file = 'db/contentful-schema.json'
|
189
206
|
@webhook_jobs = []
|
190
207
|
@store_factory = WCC::Contentful::Store::Factory.new(self, :direct)
|
208
|
+
@sync_retry_limit = 3
|
209
|
+
@sync_retry_wait = 1.second
|
191
210
|
end
|
192
211
|
|
193
212
|
# Validates the configuration, raising ArgumentError if anything is wrong. This
|
@@ -36,7 +36,7 @@ class WCC::Contentful::DownloadsSchema
|
|
36
36
|
begin
|
37
37
|
JSON.parse(File.read(@file))
|
38
38
|
rescue JSON::ParserError
|
39
|
-
return true
|
39
|
+
return true # rubocop:disable Lint/NoReturnInBeginEndBlocks
|
40
40
|
end
|
41
41
|
|
42
42
|
existing_cts = contents['contentTypes'].sort_by { |ct| ct.dig('sys', 'id') }
|
@@ -83,13 +83,14 @@ class WCC::Contentful::DownloadsSchema
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def deep_contains_all(expected, actual)
|
86
|
-
|
86
|
+
case expected
|
87
|
+
when Array
|
87
88
|
expected.each_with_index do |val, i|
|
88
89
|
return false unless actual[i]
|
89
90
|
return false unless deep_contains_all(val, actual[i])
|
90
91
|
end
|
91
92
|
true
|
92
|
-
|
93
|
+
when Hash
|
93
94
|
expected.each do |(key, val)|
|
94
95
|
return false unless actual.key?(key)
|
95
96
|
return false unless deep_contains_all(val, actual[key])
|
@@ -107,6 +108,6 @@ class WCC::Contentful::DownloadsSchema
|
|
107
108
|
# only in its treatment of empty arrays in the "validations" field.
|
108
109
|
json_string = json_string.gsub(/\[\n\n\s+\]/, '[]')
|
109
110
|
# contentful-shell also adds a newline at the end.
|
110
|
-
json_string
|
111
|
+
"#{json_string}\n"
|
111
112
|
end
|
112
113
|
end
|
@@ -6,9 +6,7 @@ module WCC::Contentful
|
|
6
6
|
config = WCC::Contentful.configuration
|
7
7
|
|
8
8
|
jobs = []
|
9
|
-
if WCC::Contentful::Services.instance.sync_engine&.should_sync?
|
10
|
-
jobs << WCC::Contentful::SyncEngine::Job
|
11
|
-
end
|
9
|
+
jobs << WCC::Contentful::SyncEngine::Job if WCC::Contentful::Services.instance.sync_engine&.should_sync?
|
12
10
|
jobs.push(*WCC::Contentful.configuration.webhook_jobs)
|
13
11
|
|
14
12
|
jobs.each do |job|
|
@@ -19,7 +17,7 @@ module WCC::Contentful
|
|
19
17
|
job.perform_later(event.to_h)
|
20
18
|
else
|
21
19
|
Rails.logger.error "Misconfigured webhook job: #{job} does not respond to " \
|
22
|
-
|
20
|
+
':perform_later'
|
23
21
|
end
|
24
22
|
rescue StandardError => e
|
25
23
|
warn "Error in job #{job}: #{e}"
|
data/lib/wcc/contentful/event.rb
CHANGED
@@ -23,9 +23,7 @@ module WCC::Contentful::Event
|
|
23
23
|
|
24
24
|
def register(constant)
|
25
25
|
name = constant.try(:type) || constant.name.demodulize
|
26
|
-
unless constant.respond_to?(:new)
|
27
|
-
raise ArgumentError, "Constant #{constant} does not define 'new'"
|
28
|
-
end
|
26
|
+
raise ArgumentError, "Constant #{constant} does not define 'new'" unless constant.respond_to?(:new)
|
29
27
|
|
30
28
|
@event_types ||= {}
|
31
29
|
@event_types[name] = constant
|
@@ -58,6 +56,7 @@ module WCC::Contentful::Event
|
|
58
56
|
attr_reader :sys
|
59
57
|
attr_reader :raw
|
60
58
|
attr_reader :source
|
59
|
+
|
61
60
|
delegate :id, to: :sys
|
62
61
|
delegate :type, to: :sys
|
63
62
|
delegate :created_at, to: :sys
|
@@ -12,8 +12,7 @@ module WCC::Contentful
|
|
12
12
|
# Raised when an entry contains a circular reference and cannot be represented
|
13
13
|
# as a flat tree.
|
14
14
|
class CircularReferenceError < StandardError
|
15
|
-
attr_reader :stack
|
16
|
-
attr_reader :id
|
15
|
+
attr_reader :stack, :id
|
17
16
|
|
18
17
|
def initialize(stack, id)
|
19
18
|
@id = id
|
@@ -25,7 +24,7 @@ module WCC::Contentful
|
|
25
24
|
return super unless stack
|
26
25
|
|
27
26
|
super + "\n " \
|
28
|
-
|
27
|
+
"#{stack.last} points to #{id} which is also it's ancestor\n " +
|
29
28
|
stack.join('->')
|
30
29
|
end
|
31
30
|
end
|
@@ -109,9 +109,7 @@ module WCC::Contentful
|
|
109
109
|
].freeze
|
110
110
|
|
111
111
|
def type=(raw_type)
|
112
|
-
unless TYPES.include?(raw_type)
|
113
|
-
raise ArgumentError, "Unknown type #{raw_type}, expected one of: #{TYPES}"
|
114
|
-
end
|
112
|
+
raise ArgumentError, "Unknown type #{raw_type}, expected one of: #{TYPES}" unless TYPES.include?(raw_type)
|
115
113
|
|
116
114
|
@type = raw_type
|
117
115
|
end
|
@@ -131,9 +129,7 @@ module WCC::Contentful
|
|
131
129
|
|
132
130
|
if raw_type = hash_or_id.delete('type')
|
133
131
|
raw_type = raw_type.to_sym
|
134
|
-
unless TYPES.include?(raw_type)
|
135
|
-
raise ArgumentError, "Unknown type #{raw_type}, expected one of: #{TYPES}"
|
136
|
-
end
|
132
|
+
raise ArgumentError, "Unknown type #{raw_type}, expected one of: #{TYPES}" unless TYPES.include?(raw_type)
|
137
133
|
|
138
134
|
@type = raw_type
|
139
135
|
end
|
@@ -7,11 +7,12 @@ module WCC::Contentful
|
|
7
7
|
def _instrumentation_event_prefix
|
8
8
|
@_instrumentation_event_prefix ||=
|
9
9
|
# WCC::Contentful => contentful.wcc
|
10
|
-
'.' + (is_a?(Class) || is_a?(Module) ? self : self.class)
|
10
|
+
'.' + (is_a?(Class) || is_a?(Module) ? self : self.class) # rubocop:disable Style/StringConcatenation
|
11
11
|
.name.parameterize.split('-').reverse.join('.')
|
12
12
|
end
|
13
13
|
|
14
14
|
attr_writer :_instrumentation
|
15
|
+
|
15
16
|
def _instrumentation
|
16
17
|
# look for per-instance instrumentation then try class level
|
17
18
|
@_instrumentation || self.class._instrumentation
|
data/lib/wcc/contentful/link.rb
CHANGED
@@ -4,9 +4,7 @@
|
|
4
4
|
# It is used internally by the Store layer to compose the resulting resolved hashes.
|
5
5
|
# But you can use it too!
|
6
6
|
class WCC::Contentful::LinkVisitor
|
7
|
-
attr_reader :entry
|
8
|
-
attr_reader :fields
|
9
|
-
attr_reader :depth
|
7
|
+
attr_reader :entry, :fields, :depth
|
10
8
|
|
11
9
|
# @param [Hash] entry The entry hash (resolved or unresolved) to walk
|
12
10
|
# @param [Array<Symbol>] The type of fields to select from the entry tree.
|
@@ -66,7 +64,7 @@ class WCC::Contentful::LinkVisitor
|
|
66
64
|
|
67
65
|
def each_field(field)
|
68
66
|
each_locale(field) do |val, locale|
|
69
|
-
if val
|
67
|
+
if val.is_a?(Array)
|
70
68
|
val.each_with_index do |v, index|
|
71
69
|
yield(v, field, locale, index) unless v.nil?
|
72
70
|
end
|
@@ -36,12 +36,8 @@ module WCC::Contentful::Middleware::Store
|
|
36
36
|
# figure out how to cache the results of a find_by query, ex:
|
37
37
|
# `find_by('slug' => '/about')`
|
38
38
|
def find_by(content_type:, filter: nil, options: nil)
|
39
|
-
if filter&.keys == ['sys.id']
|
40
|
-
|
41
|
-
# We can return just this item. Stores are not required to implement :include option.
|
42
|
-
if found = @cache.read(filter['sys.id'])
|
43
|
-
return found
|
44
|
-
end
|
39
|
+
if filter&.keys == ['sys.id'] && found = @cache.read(filter['sys.id'])
|
40
|
+
return found
|
45
41
|
end
|
46
42
|
|
47
43
|
store.find_by(content_type: content_type, filter: filter, options: options)
|
@@ -79,8 +75,8 @@ module WCC::Contentful::Middleware::Store
|
|
79
75
|
prev = @cache.read(id)
|
80
76
|
return if prev.nil? && LAZILY_CACHEABLE_TYPES.include?(type)
|
81
77
|
|
82
|
-
if (prev_rev = prev&.dig('sys', 'revision')) && (next_rev = json.dig('sys', 'revision'))
|
83
|
-
return prev
|
78
|
+
if (prev_rev = prev&.dig('sys', 'revision')) && (next_rev = json.dig('sys', 'revision')) && (next_rev < prev_rev)
|
79
|
+
return prev
|
84
80
|
end
|
85
81
|
|
86
82
|
# we also set DeletedEntry objects in the cache - no need to go hit the API when we know
|
@@ -96,9 +96,9 @@ module WCC::Contentful::Middleware::Store
|
|
96
96
|
|
97
97
|
def count
|
98
98
|
if middleware.has_select?
|
99
|
-
raise NameError, "Count cannot be determined because the middleware '#{middleware}'" \
|
100
|
-
|
101
|
-
|
99
|
+
raise NameError, "Count cannot be determined because the middleware '#{middleware}' " \
|
100
|
+
"implements the #select? method. Please use '.to_a.count' to count entries that " \
|
101
|
+
'pass the #select? method.'
|
102
102
|
end
|
103
103
|
|
104
104
|
# The wrapped query may get count from the "Total" field in the response,
|
@@ -112,9 +112,7 @@ module WCC::Contentful::Middleware::Store
|
|
112
112
|
result = wrapped_query.to_enum
|
113
113
|
result = result.select { |x| middleware.select?(x) } if middleware.has_select?
|
114
114
|
|
115
|
-
if options && options[:include]
|
116
|
-
result = result.map { |x| middleware.resolve_includes(x, options[:include]) }
|
117
|
-
end
|
115
|
+
result = result.map { |x| middleware.resolve_includes(x, options[:include]) } if options && options[:include]
|
118
116
|
|
119
117
|
result.map { |x| middleware.transform(x) }
|
120
118
|
end
|
@@ -51,9 +51,7 @@ module WCC::Contentful::ModelAPI
|
|
51
51
|
|
52
52
|
file = configuration.schema_file
|
53
53
|
schema_json = JSON.parse(File.read(file))['contentTypes']
|
54
|
-
unless schema_json
|
55
|
-
raise ArgumentError, 'Please give either a JSON array of content types or file to load from'
|
56
|
-
end
|
54
|
+
raise ArgumentError, 'Please give either a JSON array of content types or file to load from' unless schema_json
|
57
55
|
|
58
56
|
@schema = WCC::Contentful::ContentTypeIndexer.from_json_schema(schema_json).types
|
59
57
|
end
|
@@ -98,7 +96,7 @@ module WCC::Contentful::ModelAPI
|
|
98
96
|
loop do
|
99
97
|
begin
|
100
98
|
# The app may have defined a model and we haven't loaded it yet
|
101
|
-
const = parent.
|
99
|
+
const = parent.const_get(const_name)
|
102
100
|
return const if const && const < self
|
103
101
|
rescue NameError => e
|
104
102
|
raise e unless e.message =~ /uninitialized constant (.+::)*#{const_name}$/
|
@@ -158,7 +156,7 @@ module WCC::Contentful::ModelAPI
|
|
158
156
|
const_name = klass.name
|
159
157
|
begin
|
160
158
|
# the const_name is fully qualified so search from root
|
161
|
-
const = Object.
|
159
|
+
const = Object.const_get(const_name)
|
162
160
|
register_for_content_type(content_type, klass: const) if const
|
163
161
|
rescue NameError => e
|
164
162
|
msg = "Error when reloading constant #{const_name} - #{e}"
|
@@ -61,7 +61,7 @@ module WCC::Contentful
|
|
61
61
|
ct = content_type_from_raw(raw)
|
62
62
|
if ct != typedef.content_type
|
63
63
|
raise ArgumentError, 'Wrong Content Type - ' \
|
64
|
-
|
64
|
+
"'#{raw.dig('sys', 'id')}' is a #{ct}, expected #{typedef.content_type}"
|
65
65
|
end
|
66
66
|
@raw = raw.freeze
|
67
67
|
|
@@ -107,12 +107,13 @@ module WCC::Contentful
|
|
107
107
|
# array fields need to resolve to an empty array when nothing is there
|
108
108
|
raw_value = []
|
109
109
|
end
|
110
|
-
instance_variable_set(
|
110
|
+
instance_variable_set("@#{f.name}", raw_value)
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
114
|
attr_reader :sys
|
115
115
|
attr_reader :raw
|
116
|
+
|
116
117
|
delegate :id, to: :sys
|
117
118
|
delegate :created_at, to: :sys
|
118
119
|
delegate :updated_at, to: :sys
|
@@ -122,11 +123,11 @@ module WCC::Contentful
|
|
122
123
|
# Make a field for each column:
|
123
124
|
typedef.fields.each_value do |f|
|
124
125
|
name = f.name
|
125
|
-
var_name =
|
126
|
+
var_name = "@#{name}"
|
126
127
|
case f.type
|
127
128
|
when :Asset, :Link
|
128
129
|
define_method(name) do
|
129
|
-
val = instance_variable_get(var_name
|
130
|
+
val = instance_variable_get("#{var_name}_resolved")
|
130
131
|
return val if val.present?
|
131
132
|
|
132
133
|
_resolve_field(name)
|
@@ -54,17 +54,15 @@ module WCC::Contentful::ModelMethods
|
|
54
54
|
_instrument 'resolve', id: id, depth: depth, backlinks: backlinked_ids do
|
55
55
|
# use include param to do resolution
|
56
56
|
store.find_by(content_type: self.class.content_type,
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
filter: { 'sys.id' => id },
|
58
|
+
options: context.except(*MODEL_LAYER_CONTEXT_KEYS).merge!({
|
59
|
+
include: [depth, 10].min
|
60
|
+
}))
|
61
61
|
end
|
62
|
-
unless raw
|
63
|
-
raise WCC::Contentful::ResolveError, "Cannot find #{self.class.content_type} with ID #{id}"
|
64
|
-
end
|
62
|
+
raise WCC::Contentful::ResolveError, "Cannot find #{self.class.content_type} with ID #{id}" unless raw
|
65
63
|
|
66
64
|
@raw = raw.freeze
|
67
|
-
links.each { |f| instance_variable_set(
|
65
|
+
links.each { |f| instance_variable_set("@#{f}", raw.dig('fields', f, sys.locale)) }
|
68
66
|
end
|
69
67
|
|
70
68
|
links.each { |f| _resolve_field(f, depth, context, options) }
|
@@ -142,7 +140,7 @@ module WCC::Contentful::ModelMethods
|
|
142
140
|
def _resolve_field(field_name, depth = 1, context = {}, options = {})
|
143
141
|
return if depth <= 0
|
144
142
|
|
145
|
-
var_name =
|
143
|
+
var_name = "@#{field_name}"
|
146
144
|
return unless val = instance_variable_get(var_name)
|
147
145
|
|
148
146
|
context = sys.context.to_h.merge(context)
|
@@ -182,17 +180,17 @@ module WCC::Contentful::ModelMethods
|
|
182
180
|
val = _try_map(val) { |v| load.call(v) }
|
183
181
|
val = val.compact if val.is_a? Array
|
184
182
|
|
185
|
-
instance_variable_set(var_name
|
183
|
+
instance_variable_set("#{var_name}_resolved", val)
|
186
184
|
rescue WCC::Contentful::CircularReferenceError
|
187
185
|
raise unless options[:circular_reference] == :ignore
|
188
186
|
end
|
189
187
|
end
|
190
188
|
|
191
189
|
def _resolved_field?(field_name, depth = 1)
|
192
|
-
var_name =
|
190
|
+
var_name = "@#{field_name}"
|
193
191
|
raw = instance_variable_get(var_name)
|
194
192
|
return true if raw.nil? || (raw.is_a?(Array) && raw.all?(&:nil?))
|
195
|
-
return false unless val = instance_variable_get(var_name
|
193
|
+
return false unless val = instance_variable_get("#{var_name}_resolved")
|
196
194
|
return true if depth <= 1
|
197
195
|
|
198
196
|
return val.resolved?(depth: depth - 1) unless val.is_a? Array
|
@@ -66,7 +66,7 @@ module WCC::Contentful::ModelSingletonMethods
|
|
66
66
|
new(result, options) if result
|
67
67
|
end
|
68
68
|
|
69
|
-
def inherited(subclass)
|
69
|
+
def inherited(subclass) # rubocop:disable Lint/MissingSuper
|
70
70
|
# If another different class is already registered for this content type,
|
71
71
|
# don't auto-register this one.
|
72
72
|
return if model_namespace.registered?(content_type)
|
@@ -37,9 +37,7 @@ module WCC::Contentful::RichText
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def tokenize(raw, context = nil)
|
40
|
-
unless raw['nodeType'] == node_type
|
41
|
-
raise ArgumentError, "Expected '#{node_type}', got '#{raw['nodeType']}'"
|
42
|
-
end
|
40
|
+
raise ArgumentError, "Expected '#{node_type}', got '#{raw['nodeType']}'" unless raw['nodeType'] == node_type
|
43
41
|
|
44
42
|
values =
|
45
43
|
members.map do |symbol|
|
data/lib/wcc/contentful/rspec.rb
CHANGED
@@ -13,9 +13,7 @@ module WCC::Contentful::RSpec
|
|
13
13
|
# stubs the Model API to return that content type for `.find` and `.find_by`
|
14
14
|
# query methods.
|
15
15
|
def contentful_stub(const, **attrs)
|
16
|
-
unless const.respond_to?(:content_type_definition)
|
17
|
-
const = WCC::Contentful::Model.resolve_constant(const.to_s)
|
18
|
-
end
|
16
|
+
const = WCC::Contentful::Model.resolve_constant(const.to_s) unless const.respond_to?(:content_type_definition)
|
19
17
|
instance = contentful_create(const, **attrs)
|
20
18
|
|
21
19
|
# mimic what's going on inside model_singleton_methods.rb
|
@@ -132,6 +132,15 @@ module WCC::Contentful
|
|
132
132
|
# Allow it to be injected into a store
|
133
133
|
alias_method :_instrumentation, :instrumentation
|
134
134
|
|
135
|
+
# Gets the configured logger, defaulting to Rails.logger in a rails context,
|
136
|
+
# or logging to STDERR in a non-rails context.
|
137
|
+
def logger
|
138
|
+
@logger ||=
|
139
|
+
configuration.logger ||
|
140
|
+
(Rails.logger if defined?(Rails)) ||
|
141
|
+
Logger.new($stderr)
|
142
|
+
end
|
143
|
+
|
135
144
|
##
|
136
145
|
# This method enables simple dependency injection -
|
137
146
|
# If the target has a setter matching the name of one of the services,
|