wcc-contentful 0.4.0.pre.rc → 1.0.0.pre.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +5 -5
  2. data/Guardfile +43 -0
  3. data/README.md +101 -12
  4. data/app/controllers/wcc/contentful/webhook_controller.rb +25 -24
  5. data/app/jobs/wcc/contentful/webhook_enable_job.rb +36 -2
  6. data/config/routes.rb +1 -1
  7. data/doc/wcc-contentful.png +0 -0
  8. data/lib/tasks/download_schema.rake +12 -0
  9. data/lib/wcc/contentful.rb +70 -16
  10. data/lib/wcc/contentful/active_record_shim.rb +72 -0
  11. data/lib/wcc/contentful/configuration.rb +177 -46
  12. data/lib/wcc/contentful/content_type_indexer.rb +14 -0
  13. data/lib/wcc/contentful/downloads_schema.rb +112 -0
  14. data/lib/wcc/contentful/engine.rb +33 -14
  15. data/lib/wcc/contentful/event.rb +171 -0
  16. data/lib/wcc/contentful/events.rb +41 -0
  17. data/lib/wcc/contentful/exceptions.rb +3 -0
  18. data/lib/wcc/contentful/indexed_representation.rb +2 -2
  19. data/lib/wcc/contentful/instrumentation.rb +31 -0
  20. data/lib/wcc/contentful/link.rb +28 -0
  21. data/lib/wcc/contentful/link_visitor.rb +122 -0
  22. data/lib/wcc/contentful/middleware.rb +7 -0
  23. data/lib/wcc/contentful/middleware/store.rb +158 -0
  24. data/lib/wcc/contentful/middleware/store/caching_middleware.rb +114 -0
  25. data/lib/wcc/contentful/model.rb +37 -3
  26. data/lib/wcc/contentful/model_builder.rb +1 -0
  27. data/lib/wcc/contentful/model_methods.rb +40 -15
  28. data/lib/wcc/contentful/model_singleton_methods.rb +47 -30
  29. data/lib/wcc/contentful/rake.rb +3 -0
  30. data/lib/wcc/contentful/rspec.rb +13 -8
  31. data/lib/wcc/contentful/services.rb +61 -27
  32. data/lib/wcc/contentful/simple_client.rb +81 -25
  33. data/lib/wcc/contentful/simple_client/management.rb +43 -10
  34. data/lib/wcc/contentful/simple_client/response.rb +61 -22
  35. data/lib/wcc/contentful/simple_client/typhoeus_adapter.rb +17 -17
  36. data/lib/wcc/contentful/store.rb +7 -66
  37. data/lib/wcc/contentful/store/README.md +85 -0
  38. data/lib/wcc/contentful/store/base.rb +34 -119
  39. data/lib/wcc/contentful/store/cdn_adapter.rb +71 -12
  40. data/lib/wcc/contentful/store/factory.rb +186 -0
  41. data/lib/wcc/contentful/store/instrumentation.rb +55 -0
  42. data/lib/wcc/contentful/store/interface.rb +82 -0
  43. data/lib/wcc/contentful/store/memory_store.rb +27 -24
  44. data/lib/wcc/contentful/store/postgres_store.rb +253 -107
  45. data/lib/wcc/contentful/store/postgres_store/schema_1.sql +73 -0
  46. data/lib/wcc/contentful/store/postgres_store/schema_2.sql +21 -0
  47. data/lib/wcc/contentful/store/query.rb +246 -0
  48. data/lib/wcc/contentful/store/query/interface.rb +63 -0
  49. data/lib/wcc/contentful/store/rspec_examples.rb +48 -0
  50. data/lib/wcc/contentful/store/rspec_examples/basic_store.rb +629 -0
  51. data/lib/wcc/contentful/store/rspec_examples/include_param.rb +283 -0
  52. data/lib/wcc/contentful/store/rspec_examples/nested_queries.rb +342 -0
  53. data/lib/wcc/contentful/sync_engine.rb +181 -0
  54. data/lib/wcc/contentful/test/attributes.rb +17 -5
  55. data/lib/wcc/contentful/test/factory.rb +22 -46
  56. data/lib/wcc/contentful/version.rb +1 -1
  57. data/wcc-contentful.gemspec +14 -11
  58. metadata +201 -146
  59. data/Gemfile +0 -6
  60. data/app/jobs/wcc/contentful/delayed_sync_job.rb +0 -63
  61. data/lib/wcc/contentful/client_ext.rb +0 -28
  62. data/lib/wcc/contentful/graphql.rb +0 -14
  63. data/lib/wcc/contentful/graphql/builder.rb +0 -177
  64. data/lib/wcc/contentful/graphql/types.rb +0 -54
  65. data/lib/wcc/contentful/simple_client/http_adapter.rb +0 -24
  66. data/lib/wcc/contentful/store/lazy_cache_store.rb +0 -161
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: dbe6cdec1d0756eb9c1f8930efb8023ebbf6a758
4
- data.tar.gz: 61fadc6215d698b8865dd7ad0a1c2e3c8dd8f26f
2
+ SHA256:
3
+ metadata.gz: e8c289b7bbddc39150c9ab86fb781e4dcdd740153a6e39906f438caa11740077
4
+ data.tar.gz: 36d446fb8abe8b7dbed82f68d36280d85528f4ba60a9af2707bbccbdb4a04794
5
5
  SHA512:
6
- metadata.gz: 3d9ec54fe32c9380048236927fbcfd77a44e3c499327520054b61ae3976a561cdf7a1d7bad916b6f33b839963877f7d1c7e53067cebd8e646c74bb2d335c9606
7
- data.tar.gz: aed63f65c37498f9ebee35f768c49c5be763e32032714321aaa8f35eba07d8f10d033082b85401e51cb4e8c964698a11d216eb6af885707ff6ec5bd43cefccb9
6
+ metadata.gz: a3a992e38c9688f7bc0834bf0629c5df5e6d54fdca044295a534d741ce3fc6c6e4017a9a48ba65c765af91c6ff9733ec5469ecb0aaa5a1302e371c6fd3325de1
7
+ data.tar.gz: 90aa3d052268446d7d1bb15cea05048b643904026d8406ea274045db6a68b3c395b09e60178a13f028e3238a8a3606c3f63abc58a47ba5c8b822834b6a8c3064
data/Guardfile CHANGED
@@ -3,6 +3,39 @@
3
3
 
4
4
  # To run, use `bundle exec guard`.
5
5
 
6
+ def watch_async(regexp)
7
+ raise ArgumentError, "No block given" unless block_given?
8
+ match_queue = Queue.new
9
+
10
+ watch(regexp) do |match|
11
+ # Producer - add matches to the match queue
12
+ match_queue << match
13
+ nil
14
+ end
15
+
16
+ # Consumer - process matches as a batch
17
+ Thread.new do
18
+ loop do
19
+ matches = []
20
+ matches << match_queue.pop
21
+
22
+ loop do
23
+ begin
24
+ matches << match_queue.pop(true)
25
+ rescue ThreadError
26
+ break
27
+ end
28
+ end
29
+
30
+ begin
31
+ yield matches if matches.length > 0
32
+ rescue StandardError => ex
33
+ STDERR.puts "Error! #{ex}"
34
+ end
35
+ end
36
+ end
37
+ end
38
+
6
39
  group :red_green_refactor, halt_on_fail: true do
7
40
  guard :rspec, cmd: 'bundle exec rspec' do
8
41
  require 'guard/rspec/dsl'
@@ -46,6 +79,16 @@ group :red_green_refactor, halt_on_fail: true do
46
79
  watch(%r{.+\.rb$})
47
80
  watch(%r{(?:.+/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) }
48
81
  end
82
+
83
+ guard :shell, all_on_start: false do
84
+ watch_async(%r{app/views/(.+\.html.*\.erb)}) { |matches|
85
+
86
+ matches = matches.map { |m| File.absolute_path(m[0]) }
87
+ Dir.chdir('..') {
88
+ system("bundle exec erblint #{matches.join(' ')}")
89
+ }
90
+ }
91
+ end
49
92
  end
50
93
 
51
94
  group :autofix do
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- [![Gem Version](https://badge.fury.io/rb/wcc-contentful.svg)](https://badge.fury.io/rb/wcc-contentful)
2
- [![CircleCI](https://circleci.com/gh/watermarkchurch/wcc-contentful.svg?style=svg)](https://circleci.com/gh/watermarkchurch/wcc-contentful)
1
+ [![Gem Version](https://badge.fury.io/rb/wcc-contentful.svg)](https://rubygems.org/gems/wcc-contentful)
2
+ [![Build Status](https://travis-ci.org/watermarkchurch/wcc-contentful.svg?branch=master)](https://travis-ci.org/watermarkchurch/wcc-contentful)
3
3
  [![Coverage Status](https://coveralls.io/repos/github/watermarkchurch/wcc-contentful/badge.svg?branch=master)](https://coveralls.io/github/watermarkchurch/wcc-contentful?branch=master)
4
4
 
5
- Full documentation: https://www.rubydoc.info/github/watermarkchurch/wcc-contentful
5
+ Full documentation: https://www.rubydoc.info/gems/wcc-contentful
6
6
 
7
7
  # WCC::Contentful
8
8
 
@@ -14,17 +14,26 @@ Add this line to your application's Gemfile:
14
14
  gem 'wcc-contentful', require: 'wcc/contentful/rails'
15
15
  ```
16
16
 
17
- And then execute:
17
+ If you're not using rails, exclude the `require:` parameter.
18
18
 
19
- $ bundle
19
+ ```ruby
20
+ gem 'wcc-contentful'
21
+ ```
20
22
 
23
+ And then execute:
24
+ ```
25
+ $ bundle
26
+ ```
21
27
  Or install it yourself as:
22
-
28
+ ```
23
29
  $ gem install wcc-contentful
30
+ ```
24
31
 
25
32
  ## Configure
26
33
 
34
+ Put this in an initializer:
27
35
  ```ruby
36
+ # config/initializers/wcc_contentful.rb
28
37
  WCC::Contentful.configure do |config|
29
38
  config.access_token = <CONTENTFUL_ACCESS_TOKEN>
30
39
  config.space = <CONTENTFUL_SPACE_ID>
@@ -33,13 +42,16 @@ end
33
42
  WCC::Contentful.init!
34
43
  ```
35
44
 
45
+ All configuration options can be found [in the rubydoc](https://www.rubydoc.info/gems/wcc-contentful/WCC/Contentful/Configuration) under
46
+ {WCC::Contentful::Configuration}
47
+
36
48
  ## Usage
37
49
 
38
50
  ### WCC::Contentful::Model API
39
51
 
40
52
  The WCC::Contentful::Model API exposes Contentful data as a set of dynamically
41
53
  generated Ruby objects. These objects are based on the content types in your
42
- Contentful space. All these objects are generated by WCC::Contentful.init!
54
+ Contentful space. All these objects are generated by `WCC::Contentful.init!`
43
55
 
44
56
  The following examples show how to use this API to find entries of the `page`
45
57
  content type:
@@ -164,7 +176,8 @@ response.includes
164
176
 
165
177
  The client handles Paging automatically within the lazy iterator returned by #items.
166
178
  This lazy iterator does not respect the `limit` param - that param is only passed
167
- through to the API to set the page size.
179
+ through to the API to set the page size. If you truly want a limited subset of
180
+ response items, use [`response.items.take(n)`](https://ruby-doc.org/core-2.5.3/Enumerable.html#method-i-take)
168
181
 
169
182
  Entries included via the `include` parameter are made available on the #includes
170
183
  field. This is a hash of `<entry ID> => <raw entry>` and makes it easy to grab
@@ -211,6 +224,10 @@ class MyJob < ApplicationJob
211
224
  end
212
225
  ```
213
226
 
227
+ ## Architecture
228
+
229
+ ![wcc-contentful diagram](./doc/wcc-contentful.png)
230
+
214
231
  ## Test Helpers
215
232
 
216
233
  To use the test helpers, include the following in your rails_helper.rb:
@@ -239,7 +256,7 @@ instance.other_optional_field
239
256
  # => nil
240
257
 
241
258
  instance.not_a_field
242
- # NoMethodError: undefined method `not_a_field' for #<Menu:0x00007fbac81ee490>
259
+ # NoMethodError: undefined method `not_a_field' for #<MyContentType:0x00007fbac81ee490>
243
260
 
244
261
  ##
245
262
  # Builds a rspec double of the Contentful model for the given content_type.
@@ -251,6 +268,9 @@ dbl = contentful_double('my-content-type', my_field: 'other-value')
251
268
  dbl.my_field
252
269
  # => "other-value"
253
270
 
271
+ dbl.other_optional_field
272
+ # => nil
273
+
254
274
  dbl.not_a_field
255
275
  # => #<Double (anonymous)> received unexpected message :not_a_field with (no args)
256
276
 
@@ -270,12 +290,81 @@ MyContentType.find_by(my_field: 'test') == stubbed
270
290
  # => true
271
291
  ```
272
292
 
293
+ ## Advanced Configuration Example
273
294
 
274
- ## Development
295
+ Here's an example containing all the configuration options, and a sample setup for
296
+ automatic deployment to Heroku. This is intended to make you aware of what is possible,
297
+ and not as a general recommendation of what your setup should look like.
298
+
299
+ ```ruby
300
+ # config/initializers/wcc_contentful.rb
301
+ WCC::Contentful.configure do |config|
302
+ config.access_token = ENV['CONTENTFUL_ACCESS_TOKEN']
303
+ config.space = ENV['CONTENTFUL_SPACE_ID']
304
+ config.environment = ENV['CONTENTFUL_ENVIRONMENT']
305
+ config.preview_token = ENV['CONTENTFUL_PREVIEW_ACCESS_TOKEN']
306
+
307
+ # You may or may not want to provide this to your production server...
308
+ config.management_token = ENV['CONTENTFUL_MANAGEMENT_TOKEN'] unless Rails.env.production?
309
+
310
+ config.app_url = "https://#{ENV['HOSTNAME']}"
311
+ config.webhook_username = 'my-app-webhook'
312
+ config.webhook_password = Rails.application.secrets.webhook_password
313
+ config.webhook_jobs << MyOnWebhookJob
314
+
315
+ config.store = :lazy_sync, Rails.cache if Rails.env.production?
316
+ # config.store = MyCustomStore.new
317
+
318
+ # Use a custom Faraday connection
319
+ config.connection = Faraday.new do |builder|
320
+ f.request :retry
321
+ f.request MyFaradayRequestAdapter.new
322
+ ...
323
+ end
324
+ # OR implement some adapter like this to use another HTTP client
325
+ config.connection = MyNetHttpAdapter.new
326
+
327
+ config.update_schema_file = :never
328
+ end
329
+
330
+ WCC::Contentful.init!
331
+ ```
332
+
333
+ For Heroku:
334
+
335
+ ```yaml
336
+ # Procfile
337
+ web: bundle exec rails s
338
+ worker: bundle exec sidekiq
339
+ release: bin/release
340
+ ```
275
341
 
276
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
342
+ ```sh
343
+ # bin/release
344
+ #!/bin/sh
345
+
346
+ set -e
347
+
348
+ echo "Migrating database..."
349
+ bin/rake db:migrate
350
+
351
+ echo "Migrating contentful..."
352
+ migrations_to_be_run=$( ... ) # somehow figure this out
353
+ node_modules/.bin/contentful-migration \
354
+ -s $CONTENTFUL_SPACE_ID -a $CONTENTFUL_MANAGEMENT_TOKEN \
355
+ -y -p "$migrations_to_be_run"
356
+
357
+ echo "Updating schema file..."
358
+ rake wcc_contentful:download_schema
359
+ ```
360
+
361
+ All configuration options can be found [in the rubydoc](https://www.rubydoc.info/gems/wcc-contentful/WCC/Contentful/Configuration) under
362
+ {WCC::Contentful::Configuration}
363
+
364
+
365
+ ## Development
277
366
 
278
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
367
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
279
368
 
280
369
  ## Contributing
281
370
 
@@ -8,6 +8,7 @@ module WCC::Contentful
8
8
  # the jobs configured in {WCC::Contentful::Configuration WCC::Contentful::Configuration#webhook_jobs}
9
9
  class WebhookController < ApplicationController
10
10
  include WCC::Contentful::ServiceAccessors
11
+ include Wisper::Publisher
11
12
 
12
13
  before_action :authorize_contentful
13
14
  protect_from_forgery unless: -> { request.format.json? }
@@ -17,27 +18,17 @@ module WCC::Contentful
17
18
  end
18
19
 
19
20
  def receive
20
- event = params.require('webhook').permit!
21
- event.require('sys').require(%w[id type])
22
- event = event.to_h
23
-
24
- # Immediately update the store, we may update again later using DelayedSyncJob.
25
- store.index(event) if store.respond_to?(:index)
26
-
27
- jobs.each do |job|
28
- begin
29
- if job.respond_to?(:perform_later)
30
- job.perform_later(event)
31
- elsif job.respond_to?(:call)
32
- job.call(event)
33
- else
34
- Rails.logger.error "Misconfigured webhook job: #{job} does not respond to " \
35
- ':perform_later or :call'
36
- end
37
- rescue StandardError => e
38
- Rails.logger.error "Error in job #{job}: #{e}"
39
- end
40
- end
21
+ params.require('sys').require(%w[id type])
22
+ params.permit('sys', 'fields')
23
+ event = params.slice('sys', 'fields').permit!.to_h
24
+
25
+ return unless check_environment(event)
26
+
27
+ # Immediately update the store, we may update again later using SyncEngine::Job.
28
+ store.index(event) if store.index?
29
+
30
+ event = WCC::Contentful::Event.from_raw(event, source: self)
31
+ emit_event(event)
41
32
  end
42
33
 
43
34
  private
@@ -62,9 +53,19 @@ module WCC::Contentful
62
53
  render json: { msg: 'This endpoint only responds to webhooks from Contentful' }, status: 406
63
54
  end
64
55
 
65
- def jobs
66
- jobs = [WCC::Contentful::DelayedSyncJob]
67
- jobs.push(*WCC::Contentful.configuration.webhook_jobs)
56
+ def check_environment(event)
57
+ environment_id = event.dig('sys', 'environment', 'sys', 'id')
58
+ return true unless environment_id.present?
59
+
60
+ configured_environment = WCC::Contentful.configuration.environment.presence || 'master'
61
+ configured_environment.casecmp(environment_id) == 0
62
+ end
63
+
64
+ def emit_event(event)
65
+ type = event.dig('sys', 'type')
66
+ raise ArgumentError, "Unknown event type #{event}" unless type.present?
67
+
68
+ broadcast(type, event)
68
69
  end
69
70
  end
70
71
  end
@@ -7,7 +7,9 @@ module WCC::Contentful
7
7
  self.queue_adapter = :async
8
8
  queue_as :default
9
9
 
10
- def perform(args)
10
+ def perform(args = {})
11
+ args = default_configuration.merge!(args)
12
+
11
13
  client = WCC::Contentful::SimpleClient::Management.new(
12
14
  args
13
15
  )
@@ -26,7 +28,8 @@ module WCC::Contentful
26
28
  'topics' => [
27
29
  '*.publish',
28
30
  '*.unpublish'
29
- ]
31
+ ],
32
+ 'filters' => webhook_filters
30
33
  }
31
34
  body['httpBasicUsername'] = webhook_username if webhook_username.present?
32
35
  body['httpBasicPassword'] = webhook_password if webhook_password.present?
@@ -39,5 +42,36 @@ module WCC::Contentful
39
42
  raise
40
43
  end
41
44
  end
45
+
46
+ private
47
+
48
+ def default_configuration
49
+ return {} unless config = WCC::Contentful&.configuration
50
+
51
+ {
52
+ management_token: config.management_token,
53
+ app_url: config.app_url,
54
+ space: config.space,
55
+ environment: config.environment,
56
+ default_locale: config.default_locale,
57
+ connection: config.connection,
58
+ webhook_username: config.webhook_username,
59
+ webhook_password: config.webhook_password
60
+ }
61
+ end
62
+
63
+ def webhook_filters
64
+ filters = []
65
+
66
+ if (environment_id = WCC::Contentful.configuration&.environment).present?
67
+ filters << {
68
+ 'equals' => [
69
+ { 'doc' => 'sys.environment.sys.id' },
70
+ environment_id
71
+ ]
72
+ }
73
+ end
74
+ filters
75
+ end
42
76
  end
43
77
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  WCC::Contentful::Engine.routes.draw do
4
- post 'webhook/receive', to: 'webhook#receive'
4
+ post 'webhook/receive', to: 'wcc/contentful/webhook#receive'
5
5
  end
Binary file
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wcc/contentful'
4
+ require 'wcc/contentful/downloads_schema'
5
+
6
+ namespace :wcc_contentful do
7
+ desc 'Downloads the schema from the currently configured space and stores it in ' \
8
+ 'db/contentful-schema.json'
9
+ task download_schema: :environment do
10
+ WCC::Contentful::DownloadsSchema.call
11
+ end
12
+ end
@@ -5,9 +5,12 @@ require 'wcc/contentful/version'
5
5
  require 'active_support'
6
6
  require 'active_support/core_ext/object'
7
7
 
8
+ require 'wcc/contentful/active_record_shim'
8
9
  require 'wcc/contentful/configuration'
10
+ require 'wcc/contentful/downloads_schema'
9
11
  require 'wcc/contentful/exceptions'
10
12
  require 'wcc/contentful/helpers'
13
+ require 'wcc/contentful/link_visitor'
11
14
  require 'wcc/contentful/services'
12
15
  require 'wcc/contentful/simple_client'
13
16
  require 'wcc/contentful/store'
@@ -16,6 +19,9 @@ require 'wcc/contentful/model'
16
19
  require 'wcc/contentful/model_methods'
17
20
  require 'wcc/contentful/model_singleton_methods'
18
21
  require 'wcc/contentful/model_builder'
22
+ require 'wcc/contentful/sync_engine'
23
+ require 'wcc/contentful/events'
24
+ require 'wcc/contentful/middleware'
19
25
 
20
26
  # The root namespace of the wcc-contentful gem
21
27
  #
@@ -23,16 +29,33 @@ require 'wcc/contentful/model_builder'
23
29
  # initializer.
24
30
  module WCC::Contentful
25
31
  class << self
32
+ attr_reader :initialized
33
+
26
34
  # Gets the current configuration, after calling WCC::Contentful.configure
27
35
  attr_reader :configuration
28
36
 
29
37
  attr_reader :types
38
+
39
+ # Gets all queryable locales.
40
+ # Reserved for future use.
41
+ def locales
42
+ @locales ||= { 'en-US' => {} }.freeze
43
+ end
44
+
45
+ def logger
46
+ return Rails.logger if defined?(Rails)
47
+
48
+ @logger ||= Logger.new(STDERR)
49
+ end
30
50
  end
31
51
 
32
52
  # Configures the WCC::Contentful gem to talk to a Contentful space.
33
53
  # This must be called first in your initializer, before #init! or accessing the
34
54
  # client.
55
+ # See WCC::Contentful::Configuration for all configuration options.
35
56
  def self.configure
57
+ raise InitializationError, 'Cannot configure after initialization' if @initialized
58
+
36
59
  @configuration ||= Configuration.new
37
60
  yield(configuration)
38
61
 
@@ -51,29 +74,60 @@ module WCC::Contentful
51
74
  # class Page < WCC::Contentful::Model::Page; end
52
75
  # Page.find_by(slug: 'about-us')
53
76
  def self.init!
54
- raise ArgumentError, 'Please first call WCC:Contentful.configure' if configuration.nil?
77
+ raise InitializationError, 'Please first call WCC:Contentful.configure' if configuration.nil?
78
+ raise InitializationError, 'Already Initialized' if @initialized
55
79
 
56
- # we want as much as possible the raw JSON from the API so use the management
57
- # client if possible
58
- client = Services.instance.management_client ||
59
- Services.instance.client
80
+ if configuration.update_schema_file == :always ||
81
+ (configuration.update_schema_file == :if_possible && Services.instance.management_client) ||
82
+ configuration.update_schema_file == :if_missing && !File.exist?(configuration.schema_file)
60
83
 
61
- @content_types = client.content_types(limit: 1000).items
84
+ begin
85
+ downloader = WCC::Contentful::DownloadsSchema.new
86
+ downloader.update! if configuration.update_schema_file == :always || downloader.needs_update?
87
+ rescue WCC::Contentful::SimpleClient::ApiError => e
88
+ raise InitializationError, e if configuration.update_schema_file == :always
62
89
 
63
- indexer =
64
- ContentTypeIndexer.new.tap do |ixr|
65
- @content_types.each { |type| ixr.index(type) }
90
+ WCC::Contentful.logger.warn("Unable to download schema from management API - #{e.message}")
66
91
  end
67
- @types = indexer.types
92
+ end
68
93
 
69
- store = Services.instance.store
70
- if store.respond_to?(:index)
71
- # Drop an initial sync
72
- WCC::Contentful::DelayedSyncJob.perform_later
94
+ @content_types =
95
+ begin
96
+ if File.exist?(configuration.schema_file)
97
+ JSON.parse(File.read(configuration.schema_file))['contentTypes']
98
+ end
99
+ rescue JSON::ParserError
100
+ WCC::Contentful.logger.warn("Schema file invalid, ignoring it: #{configuration.schema_file}")
101
+ nil
102
+ end
103
+
104
+ if !@content_types && %i[if_possible never].include?(configuration.update_schema_file)
105
+ # Final fallback - try to grab content types from CDN. We can't update the file
106
+ # because the CDN doesn't have all the field validation info, but we can at least
107
+ # build the WCC::Contentful::Model instances.
108
+ client = Services.instance.management_client ||
109
+ Services.instance.client
110
+ begin
111
+ @content_types = client.content_types(limit: 1000).items if client
112
+ rescue WCC::Contentful::SimpleClient::ApiError => e
113
+ # indicates bad credentials
114
+ WCC::Contentful.logger.warn("Unable to load content types from API - #{e.message}")
115
+ end
73
116
  end
74
117
 
75
- WCC::Contentful::ModelBuilder.new(@types).build_models
118
+ unless @content_types
119
+ raise InitializationError, 'Unable to load content types from schema file or API!' \
120
+ ' Check your access token and space ID.'
121
+ end
76
122
 
77
- require_relative 'contentful/client_ext' if defined?(::Contentful)
123
+ indexer = ContentTypeIndexer.from_json_schema(@content_types)
124
+ @types = indexer.types
125
+
126
+ # Drop an initial sync
127
+ WCC::Contentful::SyncEngine::Job.perform_later if defined?(WCC::Contentful::SyncEngine::Job)
128
+
129
+ WCC::Contentful::ModelBuilder.new(@types).build_models
130
+ @configuration = @configuration.freeze
131
+ @initialized = true
78
132
  end
79
133
  end