Skip to content

Commit

Permalink
Merge b933c92 into f0b98a0
Browse files Browse the repository at this point in the history
  • Loading branch information
gburgett committed Mar 15, 2019
2 parents f0b98a0 + b933c92 commit eb5682a
Show file tree
Hide file tree
Showing 42 changed files with 20,071 additions and 7,727 deletions.
2 changes: 1 addition & 1 deletion wcc-contentful-app/.rspec
@@ -1,4 +1,4 @@
--require rails_helper
--require spec_helper
--format documentation
--color
--order rand
Expand Up @@ -27,13 +27,17 @@ def preview?
return super if defined?(super)

@preview ||=
if ENV['CONTENTFUL_PREVIEW_PASSWORD'].present?
params[:preview]&.chomp == ENV['CONTENTFUL_PREVIEW_PASSWORD']&.chomp
if preview_password.present?
params[:preview]&.chomp == preview_password.chomp
else
false
end
end

def preview_password
WCC::Contentful::App.configuration.preview_password
end

def page_model
WCC::Contentful::Model.resolve_constant('page')
end
Expand Down
43 changes: 42 additions & 1 deletion wcc-contentful-app/lib/wcc/contentful/app.rb
Expand Up @@ -4,12 +4,47 @@

require_relative './app/rails'
require_relative './app/exceptions'
require_relative './app/configuration'
require_relative './app/model_validators'
require_relative './ext/model'
require_relative './app/middleware/publish_at'

module WCC::Contentful::App
class << self
attr_reader :initialized

# Gets the current configuration, after calling WCC::Contentful::App.configure
attr_reader :configuration
end

def self.configure
if initialized || WCC::Contentful.initialized
raise InitializationError, 'Cannot configure after initialization'
end

WCC::Contentful.configure do |wcc_contentful_config|
if @configuration&.wcc_contentful_config != wcc_contentful_config
@configuration = Configuration.new(wcc_contentful_config)
end
yield(configuration)
end

configuration.validate!

# Inject additional configuration into WCC::Contentful
WCC::Contentful.configure do |config|
unless config.middleware.any? { |x| x.is_a? WCC::Contentful::App::Middleware::PublishAt }
config.middleware << WCC::Contentful::App::Middleware::PublishAt
end
end

configuration
end

def self.init!
raise ArgumentError, 'Please first call WCC::Contentful.init!' unless WCC::Contentful.types
raise ArgumentError, 'Please first call WCC::Contentful::App.configure' if configuration.nil?

WCC::Contentful.init!

# Extend all model types w/ validation & extra fields
WCC::Contentful.types.each_value do |t|
Expand All @@ -23,6 +58,12 @@ def self.init!
rescue StandardError
false
end

@configuration = WCC::Contentful::App::Configuration::FrozenConfiguration.new(
configuration,
WCC::Contentful.configuration
)
@initialized = true
end

def self.db_connected?
Expand Down
60 changes: 60 additions & 0 deletions wcc-contentful-app/lib/wcc/contentful/app/configuration.rb
@@ -0,0 +1,60 @@
# frozen_string_literal: true

# This object contains all the configuration options for the `wcc-contentful` gem.
class WCC::Contentful::App::Configuration
# TODO: things to configure in the app?
ATTRIBUTES = %i[
preview_password
].freeze

# Sets the password that will be checked when the query string contains `preview=`,
# if it matches, then the Contentful entries are fetched via the preview API.
attr_accessor :preview_password

attr_reader :wcc_contentful_config

delegate(*WCC::Contentful::Configuration::ATTRIBUTES, to: :wcc_contentful_config)
delegate(*(WCC::Contentful::Configuration::ATTRIBUTES.map { |a| "#{a}=" }),
to: :wcc_contentful_config)

def initialize(wcc_contentful_config)
@wcc_contentful_config = wcc_contentful_config
@preview_password = ENV['CONTENTFUL_PREVIEW_PASSWORD']
end

# Validates the configuration, raising ArgumentError if anything is wrong. This
# is called by WCC::Contentful::App.init!
def validate!
wcc_contentful_config.validate!
end

def frozen?
false
end

class FrozenConfiguration
attr_reader(*ATTRIBUTES)

attr_reader :wcc_contentful_config

delegate(*WCC::Contentful::Configuration::ATTRIBUTES, to: :wcc_contentful_config)

def initialize(configuration, frozen_wcc_contentful_config)
unless frozen_wcc_contentful_config.frozen?
raise ArgumentError, 'Please first freeze the wcc_contentful_config'
end

@wcc_contentful_config = frozen_wcc_contentful_config

ATTRIBUTES.each do |att|
val = configuration.public_send(att)
val.freeze if val.respond_to?(:freeze)
instance_variable_set("@#{att}", val)
end
end

def frozen?
true
end
end
end
118 changes: 118 additions & 0 deletions wcc-contentful-app/lib/wcc/contentful/app/middleware/publish_at.rb
@@ -0,0 +1,118 @@
# frozen_string_literal: true

module WCC::Contentful::App::Middleware
class PublishAt
include WCC::Contentful::Middleware::Store

def self.call(store, content_delivery_params, config)
# This does not apply in preview mode
return if content_delivery_params&.find { |h| h.is_a?(Hash) && (h[:preview] == true) }

super
end

def select?(entry)
publish_at = entry.dig('fields', 'publishAt', 'en-US')
unpublish_at = entry.dig('fields', 'unpublishAt', 'en-US')

after(publish_at) && before(unpublish_at)
end

def index(entry)
maybe_drop_job(entry) if entry.dig('sys', 'type') == 'Entry'

store.index(entry) if store.index?
end

private

def after(time)
return true unless time

Time.zone.now >= Time.zone.parse(time)
end

def before(time)
return true unless time

Time.zone.now <= Time.zone.parse(time)
end

if defined?(ActiveJob::Base)
def maybe_drop_job(entry)
publish_at = entry.dig('fields', 'publishAt', 'en-US')
unpublish_at = entry.dig('fields', 'unpublishAt', 'en-US')

drop_job_at(publish_at, entry) if publish_at.present? && before(publish_at)
drop_job_at(unpublish_at, entry) if unpublish_at.present? && before(unpublish_at)
end

def drop_job_at(timestamp, entry)
ts = Time.zone.parse(timestamp)
Job.set(wait_until: ts + 1.second).perform_later(entry, store)
end

class Job < ActiveJob::Base
include Wisper::Publisher

self.queue_adapter = :async

def self.cache
@cache ||= Rails.cache
end
attr_writer :cache

def initialize(*arguments)
super

subscribe(WCC::Contentful::Events.instance, with: :rebroadcast)
end

def perform(entry, store)
return unless latest_entry_version?(entry, store)

publish_at = entry.dig('fields', 'publishAt', 'en-US')
unpublish_at = entry.dig('fields', 'unpublishAt', 'en-US')
latest_event =
[publish_at, unpublish_at]
.select { |x| x.present? && Time.zone.now >= Time.zone.parse(x) }
.max

if latest_event == publish_at
emit_entry(entry)
else
emit_deleted_entry(entry)
end
end

def latest_entry_version?(entry, store)
# If the entry isn't in the backing store, then something's changed.
return false unless from_store = store.find(entry.dig('sys', 'id'))

entry.dig('sys', 'revision') >= from_store.dig('sys', 'revision')
end

def emit_entry(entry)
emit_event(entry)
end

def emit_deleted_entry(entry)
emit_event({
'sys' => entry['sys'].merge({ 'type' => 'DeletedEntry' })
})
end

def emit_event(entry)
event = WCC::Contentful::Event.from_raw(entry, source: self)
type = entry.dig('sys', 'type')
raise ArgumentError, "Unknown event type #{event}" unless type.present?

broadcast(type, event)
end
end
else
def maybe_drop_job(entry)
end
end
end
end
Expand Up @@ -2,7 +2,7 @@

require 'wcc/contentful/app/rails'

WCC::Contentful.configure do |config|
WCC::Contentful::App.configure do |config|
# Required
config.access_token = ENV['CONTENTFUL_ACCESS_TOKEN'] || 'test1234'
config.space = ENV['CONTENTFUL_SPACE_ID'] || 'test1xab'
Expand All @@ -21,5 +21,4 @@
end

# Download content types, build models, and sync content
WCC::Contentful.init!
WCC::Contentful::App.init!
Expand Up @@ -157,11 +157,8 @@ class MyPage < WCC::Contentful::Model::Page
end

def with_preview_password
previous = ENV['CONTENTFUL_PREVIEW_PASSWORD']
ENV['CONTENTFUL_PREVIEW_PASSWORD'] = 'topsecret'

allow(WCC::Contentful::App.configuration).to receive(:preview_password)
.and_return('topsecret')
yield 'topsecret'
ensure
ENV['CONTENTFUL_PREVIEW_PASSWORD'] = previous
end
end

0 comments on commit eb5682a

Please sign in to comment.