lib/pageflow/configuration.rb
module Pageflow
# Options to be defined in the pageflow initializer of the main app.
class Configuration
# Default options for paperclip attachments which are supposed to use
# s3 storage.
attr_accessor :paperclip_s3_default_options
# String to interpolate into paths of files generated by paperclip
# preprocessors. This allows to refresh cdn caches after
# reprocessing attachments.
attr_accessor :paperclip_attachments_version
# Root folder in S3 bucket to store files in. Can be used to
# separate files of multiple development instances in a shared
# development S3 bucket.
#
# @since 13.0
attr_accessor :paperclip_s3_root
# Upload options provided to direct upload form.
# Defaults to S3 storage options.
# returns a hash with keys:
# - url: The URL to use as the action of the form
# - fields: A hash of fields that will be included in the direct upload form.
# This hash should include the signed POST policy, the access key ID and
# security token (if present), etc.
# These fields will be included as input elements of type 'hidden' on the form
#
# # @since 14.0
attr_accessor :paperclip_direct_upload_options
# Refer to the pageflow initializer template for a list of
# supported options.
attr_accessor :zencoder_options
# Contains key and iv used to encrypt string
# used by SymmetricEncryption
attr_accessor :encryption_options
# A constraint used by the pageflow engine to restrict access to
# the editor related HTTP end points. This can be used to ensure
# the editor is only accessable via a certain host when different
# CNAMES are used to access the public end points of pageflow.
attr_accessor :editor_route_constraint
# The email address to use as from header in invitation mails to
# new users
attr_accessor :mailer_sender
# Extend the configuration based on feature flags set for accounts
# or entries.
#
# @example
#
# Make a widget type only available if a feature flag is set on the
# entry or its account
#
# config.features.register('some_special_widget_type' do |config
# config.widget_types.register(Pageflow::SomeSpecial.widget_type)
# end
#
# @since 0.9
# @returns [Features}
attr_reader :features
# Subscribe to hooks in order to be notified of events. Any object
# with a call method can be a subscriber
#
# Example:
#
# config.hooks.subscribe(:submit_file, -> { do_something })
#
attr_reader :hooks
# Limit the use of certain resources. Any object implementing the
# interface of Pageflow::Quota can be registered.
#
# Example:
#
# config.quotas.register(:users, UserQuota)
#
attr_accessor :quotas
# Additional themes can be registered to use custom css.
#
# Example:
#
# config.themes.register(:custom)
#
# @return [Themes]
attr_reader :themes
# Register new types of entries.
# @return [EntryTypes]
# @since 15.1
attr_reader :entry_types
# Either a lambda or an object with a `call` method taking an
# {Account} as paramater and returing the entry type that shall be
# selected by default when creating a new entry.
# @return [#call]
# @since 15.7
attr_accessor :default_entry_type
# List of {FileType} instances.
# Can be registered globally or provided by page types.
# @return [FileTypes]
attr_reader :file_types
# Used to register components whose current state must be
# persisted as part of a revision.
# @return [RevisionComponents]
attr_reader :revision_components
# Used to register new types of widgets to be displayed in entries.
# @return [WidgetTypes]
attr_reader :widget_types
# Used to register new file importers, to be used for importing files
# @return [fileImporters]
attr_reader :file_importers
# Used to add new sections to the help dialog displayed in the
# editor.
#
# @exmaple
#
# config.help_entries.register('pageflow.rainbow.help_entries.colors', priority: 11)
# config.help_entries.register('pageflow.rainbow.help_entries.colors.blue',
# parent: 'pageflow.rainbow.help_entries.colors')
#
# @since 0.7
# @return [HelpEntries]
attr_reader :help_entries
# Paperclip style definitions of thumbnails used by Pageflow.
# @return Hash
attr_accessor :thumbnail_styles
# Names of Paperclip styles that shall be rendered into entry
# specific stylesheets.
# @return Array<Symbol>
attr_accessor :css_rendered_thumbnail_styles
# Either a lambda or an object with a `match?` method, to restrict
# access to the editor routes defined by Pageflow.
#
# This can be used if published entries shall be available under
# different CNAMES but the admin and the editor shall only be
# accessible via one official url.
attr_accessor :editor_routing_constraint
# Either a lambda or an object with a `call` method taking two
# parameters: An `ActiveRecord` scope of {Pageflow::Site} records
# and an {ActionDispatch::Request} object. Has to return the scope
# in which to find sites.
#
# Defaults to {CnameSiteRequestScope} which finds sites
# based on the request subdomain. Can be used to alter the logic
# of finding a site whose home_url to redirect to when visiting
# the public root path.
#
# Example:
#
# config.site_request_scope = lambda do |sites, request|
# sites.where(id: Pageflow::Account.find_by_name!(request.subdomain).default_site_id)
# end
attr_accessor :site_request_scope
# Either a lambda or an object with a `call` method taking two
# parameters: An `ActiveRecord` scope of `Pageflow::Entry` records
# and an `ActionDispatch::Request` object. Has to return the scope
# in which to find entries.
#
# Used by all public actions that display entries to restrict the
# available entries by hostname or other request attributes.
#
# Use {#public_entry_url_options} to make sure urls of published
# entries conform twith the restrictions.
#
# Example:
#
# # Only make entries of one account available under <account.name>.example.com
# config.public_entry_request_scope = lambda do |entries, request|
# entries.includes(:account).where(pageflow_accounts: {name: request.subdomain})
# end
attr_accessor :public_entry_request_scope
# Either a lambda or an object with a `call` method taking an
# {Entry} record and an {ActionDispatch::Request} object and
# returning `nil` or a path to redirect to. Can be used in
# conjuction with {PrimaryDomainEntryRedirect} to make sure
# entries are accessed via their account's configured cname.
#
# @since 12.4
attr_accessor :public_entry_redirect
# Cache-Control header to set for published entries that have been
# published without a password. For password protected entries,
# cache control is always set to private to prevent caching
# authenticated responses in public caches like CDNs and serving
# them to unauthenticated users.
#
# Can be wrapped in a `features.register` block to use different
# caching strategies for different entries or accounts.
#
# @since 16.1
# @return [String]
attr_accessor :public_entry_cache_control_header
# Either a lambda or an object with a `call` method taking a
# {Site} as paramater and returing a hash of options used to
# construct the url of a published entry.
#
# Can be used to change the host of the url under which entries
# are available.
#
# Example:
#
# config.public_entry_url_options = lambda do |site|
# {host: "#{site.account.name}.example.com"}
# end
attr_accessor :public_entry_url_options
# Either a lambda or an object with a `call` method taking a
# {Site} as paramater and returing a hash of options used to
# construct the embed url of a published entry.
attr_accessor :entry_embed_url_options
# Either a lambda or an object with a `call` method taking a hash
# of theme option overrides and an {EntryAtRevision} and returning
# a transformed hash of overrides. Can be used to filter overrides
# based on feature flags and other entry or account traits.
attr_accessor :transform_theme_customization_overrides
# Either a lambda or an object with a `call` method taking a hash
# of theme customization files and an {EntryAtRevision} and
# returning a transformed hash of files. Can be used to filter
# files based on feature flags and other entry or account traits.
attr_accessor :transform_theme_customization_files
# Where to redirect after creating an entry.
#
# Possible values:
#
# `:admin`: Go to entry admin page (default)
# `:editor`: Open created entry in editor
attr_accessor :after_entry_create_redirect_to
# Submit video/audio encoding jobs only after the user has
# explicitly confirmed in the editor. Can either be set to a
# boolean or a lambda that is passed the file and returns a
# boolean. Defaults to false.
attr_accessor :confirm_encoding_jobs
# Controls default value of "published until" date field in editor
# publish entry view.
#
# @since 16.1
attr_accessor :default_published_until_duration_in_months
# Used by Pageflow extensions to provide new tabs to be displayed
# in the admin.
#
# @example
#
# config.admin_resource_tabs.register(:entry, Admin::CustomTab)
#
# @return [Admin::Tabs]
attr_reader :admin_resource_tabs
# Add custom form fields to admin forms.
#
# @example
#
# config.admin_form_inputs.register(:entry, :custom_field) do
#
# @since 0.9
# @return [Admin::FormInputs]
attr_reader :admin_form_inputs
# Insert additional rows into admin attributes tables.
#
# @example
#
# config.admin_attributes_table_rows.register(:entry, :custom)
# config.admin_attributes_table_rows.register(:entry, :my_attribute, after: :title)
# config.admin_attributes_table_rows.register(:entry, :some_attribute, before: :updated_at)
#
# @example Custom content
#
# config.admin_attributes_table_rows.register(:entry, :custom) do |entry|
# span(entry.custom_attribute)
# end
#
# @since 12.2
# @return [Admin::AttributesTableRows]
attr_reader :admin_attributes_table_rows
# Array of locales which can be chosen as interface language by a
# user. Defaults to `[:en, :de]`.
# @since 0.7
attr_accessor :available_locales
# Array of locales which can be chosen as interface language for
# an entry. Defaults to the locales supported by the
# `pageflow-public-i18n` gem.
# @since 0.10
attr_accessor :available_public_locales
# Array of sharing providers which can be configured on site level.
# Defaults to `[:facebook, :twitter, :linked_in, :whats_app, :telegram, :email]`.
# @since 14.1
attr_accessor :available_share_providers
# How to handle https requests for URLs which will have assets in the page.
# If you wish to serve all assets over http and prevent mixed-content warnings,
# you can force a redirect to http. The inverse is also true: you can force
# a redirect to https for all http requests.
#
# @example
#
# config.public_https_mode = :prevent (default) # => redirects https to http
# config.public_https_mode = :enforce # => redirects http to https
# config.public_https_mode = :ignore # => does nothing
# @since 0.9
attr_accessor :public_https_mode
# Meta tag defaults.
#
# These defaults will be included in the page <head> unless overriden by the Entry.
# If you set these to <tt>nil</tt> or <tt>""</tt> the meta tag won't be included.
# @since 0.10
attr_accessor :default_keywords_meta_tag
attr_accessor :default_author_meta_tag
attr_accessor :default_publisher_meta_tag
# Share provider defaults.
#
# Default share providers for new sites.
# Must be a subset or equal to `available_share_providers`
# @since 14.1
attr_accessor :default_share_providers
# Whether a user can be deleted.
#
# @example
#
# config.authorize_user_deletion =
# lambda do |user_to_delete|
# if user_to_delete.accounts.all? { |account| account.users.size > 1 }
# true
# else
# 'Last user on account. Permission denied'
# end
# end
# @since 0.11
attr_accessor :authorize_user_deletion
# Array of values that the `license` attribute on files can take.
attr_accessor :available_file_licenses
# Array of values that the `kind` attribute on text tracks can
# take. Defaults to `[:captions, :subtitles, :descriptions]`.
attr_accessor :available_text_track_kinds
# Allow one user to be member of multiple accounts. Defaults to
# true.
# @since 12.1
attr_accessor :allow_multiaccount_users
# Options hash for account admin menu. Options from config precede
# defaults.
# @since 12.1
attr_accessor :account_admin_menu_options
# Sublayer for permissions related config.
# @since 12.1
attr_reader :permissions
# Defines the editor lock polling interval.
# @return [number]
# @since 12.1
attr_accessor :edit_lock_polling_interval
# News collection to add items to. Can be used to integrate
# Pageflow with Krant (see https://github.com/codevise/krant).
# @return [#item]
# @since 12.2
attr_accessor :news
def initialize(target_type_name = nil)
@target_type_name = target_type_name
@paperclip_attachments_version = 'v1'
@paperclip_s3_root = 'main'
@paperclip_s3_default_options = Defaults::PAPERCLIP_S3_DEFAULT_OPTIONS.dup
@paperclip_direct_upload_options = lambda { |attachment|
max_upload_size = 4_294_967_296 # max file size in bytes
presigned_post_config = attachment.s3_bucket
.presigned_post(key: attachment.path,
success_action_status: '201',
acl: 'public-read',
content_length_range: 0..max_upload_size)
{
url: presigned_post_config.url,
fields: presigned_post_config.fields
}
}
@zencoder_options = {}
@encryption_options = {}
@mailer_sender = 'pageflow@example.com'
@features = Features.new
@hooks = Hooks.new
@quotas = Quotas.new
@themes = Themes.new
@entry_types = EntryTypes.new
@entry_type_configs = {}
@entry_type_configure_blocks = Hash.new { |h, k| h[k] = [] }
@file_types = FileTypes.new
@widget_types = WidgetTypes.new
@file_importers = FileImporters.new
@help_entries = HelpEntries.new
@revision_components = RevisionComponents.new
@thumbnail_styles = Defaults::THUMBNAIL_STYLES.dup
@css_rendered_thumbnail_styles = Defaults::CSS_RENDERED_THUMBNAIL_STYLES.dup
@site_request_scope = CnameSiteRequestScope.new
@public_entry_request_scope = lambda { |entries, request| entries }
@public_entry_redirect = ->(_entry, _request) { nil }
@public_entry_url_options = Pageflow::SitesHelper::DEFAULT_PUBLIC_ENTRY_OPTIONS
@entry_embed_url_options = {protocol: 'https'}
@transform_theme_customization_overrides = ->(overrides, _entry) { overrides }
@transform_theme_customization_files = ->(files, _entry) { files }
@after_entry_create_redirect_to = :admin
@confirm_encoding_jobs = false
@default_published_until_duration_in_months = 12
@admin_resource_tabs = Pageflow::Admin::Tabs.new
@admin_form_inputs = Pageflow::Admin::FormInputs.new
@admin_attributes_table_rows = Pageflow::Admin::AttributesTableRows.new
@available_locales = [:en, :de]
@available_public_locales = PublicI18n.available_locales
@available_share_providers = [:email, :facebook, :linked_in, :twitter, :telegram, :whats_app]
@public_https_mode = :prevent
@default_keywords_meta_tag = 'pageflow, multimedia, reportage'
@default_author_meta_tag = 'Pageflow'
@default_publisher_meta_tag = 'Pageflow'
@default_share_providers = @available_share_providers
@authorize_user_deletion = lambda { |_user| true }
@available_file_licenses = [
:cc_by_4, :cc_by_sa_4, :cc_by_nc_4, :cc_by_nc_sa_4, :cc_by_nd_4, :cc_by_nc_nd_4
]
@available_text_track_kinds = [:captions, :subtitles, :descriptions]
@allow_multiaccount_users = true
@account_admin_menu_options = {}
@permissions = Permissions.new
@edit_lock_polling_interval = 15.seconds
end
# Activate a plugin.
#
# @param [Plugin] plugin
# @since 0.7
def plugin(plugin)
plugin.configure(self)
end
# Provide backwards compatibility as long as paged entry type has
# not been extracted completely. Prefer accessing entry type
# specific config via {#for_entry_type} for new code.
#
# @return {PageTypes}
# @since 0.7
def page_types
get_entry_type_config(PageflowPaged.entry_type).page_types
end
# @deprecated Use `config.page_types.register` instead.
def register_page_type(page_type)
ActiveSupport::Deprecation.warn('Pageflow::Configuration#register_page_type is deprecated. Use config.page_types.register instead.', caller)
page_types.register(page_type)
end
# @deprecated Pageflow now supports direct uploads to S3 via signed post requests.
# Please change your forms accordingly.
def paperclip_filesystem_root
ActiveSupport::Deprecation.warn('Pageflow::Configuration#paperclip_filesystem_root is deprecated.', caller)
end
def paperclip_filesystem_root=(_val)
ActiveSupport::Deprecation.warn('Pageflow::Configuration#paperclip_filesystem_root is deprecated.', caller)
end
# Scope configuration to entries of a certain entry type or access
# entry type specific configuration. When building a configuration
# object for an entry, the passed block is only evaluated when
# types match. When building `Pageflow.config`, all
# `for_entry_type` blocks are evaluated.
#
# @param [EntryType] type
#
# @yieldparam [EntryTypeConfiguration] entry_type_config -
# Instance of configuration class passed as `configuration`
# option during registration of entry type.
#
# @since 15.1
def for_entry_type(type)
return if @target_type_name && @target_type_name != type.name
yield get_entry_type_config(type)
end
# @api private
def get_entry_type_config(type)
@entry_type_configs[type.name] ||= type.configuration.new(self, type)
end
# @api private
def lint!
@features.lint!
end
# @api private
def confirm_encoding_jobs?(file)
if confirm_encoding_jobs.respond_to?(:call)
confirm_encoding_jobs.call(file)
else
confirm_encoding_jobs
end
end
# @api private
def site_url_options(site)
options = public_entry_url_options
options.respond_to?(:call) ? options.call(site) : options
end
# @api private
def enable_features(names)
features.enable(names, FeatureLevelConfiguration.new(self))
end
# @api private
def enable_all_features
features.enable_all(FeatureLevelConfiguration.new(self))
end
# Restricts the configuration interface to those parts which can
# be used from inside features.
FeatureLevelConfiguration = Struct.new(:config) do
delegate :admin_attributes_table_rows, to: :config
delegate :admin_form_inputs, to: :config
delegate :entry_types, to: :config
delegate :file_importers, to: :config
delegate :help_entries, to: :config
delegate :page_types, to: :config
delegate :themes, to: :config
delegate :widget_types, to: :config
delegate :public_entry_cache_control_header=, to: :config
delegate :for_entry_type, to: :config
end
# @api private
class ConfigView
def initialize(config, entry_type)
@config = config
@entry_type_config = config.get_entry_type_config(entry_type)
end
def method_missing(method, *args)
if @config.respond_to?(method)
@config.send(method, *args)
elsif @entry_type_config.respond_to?(method)
@entry_type_config.send(method, *args)
else
super
end
end
def respond_to_missing?(method_name, include_private = false)
@config.respond_to?(method_name) ||
@entry_type_config.respond_to?(method_name) ||
super
end
end
end
end