mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-04-07 07:36:58 +00:00
Merge pull request #5870 from luisramos0/prefs
[Bye bye Spree] Bring models app_configuration and preference from spree_core
This commit is contained in:
BIN
app/assets/images/ofn-logo.png
Normal file
BIN
app/assets/images/ofn-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
148
app/models/spree/app_configuration.rb
Normal file
148
app/models/spree/app_configuration.rb
Normal file
@@ -0,0 +1,148 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# This is the primary location for defining spree preferences
|
||||
#
|
||||
# This file allows us to add global configuration variables, which
|
||||
# we can allow to be modified in the UI by adding appropriate form
|
||||
# elements to existing or new configuration pages.
|
||||
#
|
||||
# The expectation is that this is created once and stored in
|
||||
# the spree environment
|
||||
#
|
||||
# setters:
|
||||
# a.color = :blue
|
||||
# a[:color] = :blue
|
||||
# a.set :color = :blue
|
||||
# a.preferred_color = :blue
|
||||
#
|
||||
# getters:
|
||||
# a.color
|
||||
# a[:color]
|
||||
# a.get :color
|
||||
# a.preferred_color
|
||||
#
|
||||
module Spree
|
||||
class AppConfiguration < Preferences::Configuration
|
||||
# Should state/state_name be required
|
||||
preference :address_requires_state, :boolean, default: true
|
||||
preference :admin_interface_logo, :string, default: 'ofn-logo.png'
|
||||
preference :admin_products_per_page, :integer, default: 10
|
||||
# Should only be true if you don't need to track inventory
|
||||
preference :allow_backorder_shipping, :boolean, default: false
|
||||
preference :allow_checkout_on_gateway_error, :boolean, default: false
|
||||
preference :allow_guest_checkout, :boolean, default: true
|
||||
preference :allow_ssl_in_development_and_test, :boolean, default: false
|
||||
preference :allow_ssl_in_production, :boolean, default: true
|
||||
preference :allow_ssl_in_staging, :boolean, default: true
|
||||
# Automatically capture the credit card (as opposed to just authorize and capture later)
|
||||
preference :auto_capture, :boolean, default: false
|
||||
# Replace with the name of a zone if you would like to limit the countries
|
||||
preference :checkout_zone, :string, default: nil
|
||||
preference :currency, :string, default: "USD"
|
||||
preference :currency_decimal_mark, :string, default: "."
|
||||
preference :currency_symbol_position, :string, default: "before"
|
||||
preference :currency_thousands_separator, :string, default: ","
|
||||
preference :display_currency, :boolean, default: false
|
||||
preference :default_country_id, :integer
|
||||
preference :default_meta_description, :string, default: 'OFN demo site'
|
||||
preference :default_meta_keywords, :string, default: 'ofn, demo'
|
||||
preference :default_seo_title, :string, default: ''
|
||||
preference :hide_cents, :boolean, default: false
|
||||
preference :layout, :string, default: 'darkswarm'
|
||||
preference :logo, :string, default: 'ofn-logo.png'
|
||||
|
||||
# Maximum nesting level in taxons menu
|
||||
preference :max_level_in_taxons_menu, :integer, default: 1
|
||||
preference :orders_per_page, :integer, default: 15
|
||||
preference :prices_inc_tax, :boolean, default: false
|
||||
preference :products_per_page, :integer, default: 12
|
||||
preference :redirect_https_to_http, :boolean, default: false
|
||||
preference :require_master_price, :boolean, default: true
|
||||
preference :shipment_inc_vat, :boolean, default: false
|
||||
# Request instructions/info for shipping
|
||||
preference :shipping_instructions, :boolean, default: false
|
||||
# Displays variant full price or difference with product price.
|
||||
preference :show_variant_full_price, :boolean, default: false
|
||||
preference :show_products_without_price, :boolean, default: false
|
||||
preference :show_raw_product_description, :boolean, default: false
|
||||
preference :site_name, :string, default: 'OFN Demo Site'
|
||||
preference :site_url, :string, default: 'demo.openfoodnetwork.org'
|
||||
preference :tax_using_ship_address, :boolean, default: true
|
||||
# Determines whether to track on_hand values for variants / products.
|
||||
preference :track_inventory_levels, :boolean, default: true
|
||||
|
||||
# Preferences related to image settings
|
||||
preference :attachment_default_url, :string,
|
||||
default: '/spree/products/:id/:style/:basename.:extension'
|
||||
preference :attachment_path, :string,
|
||||
default: ':rails_root/public/spree/products/:id/:style/:basename.:extension'
|
||||
preference :attachment_url, :string,
|
||||
default: '/spree/products/:id/:style/:basename.:extension'
|
||||
preference :attachment_styles, :string,
|
||||
default: "{\"mini\":\"48x48>\",\"small\":\"100x100>\",\"product\":\"240x240>\",\"large\":\"600x600>\"}"
|
||||
preference :attachment_default_style, :string, default: 'product'
|
||||
preference :s3_access_key, :string
|
||||
preference :s3_bucket, :string
|
||||
preference :s3_secret, :string
|
||||
preference :s3_headers, :string, default: "{\"Cache-Control\":\"max-age=31557600\"}"
|
||||
preference :use_s3, :boolean, default: false # Use S3 for images rather than the file system
|
||||
preference :s3_protocol, :string
|
||||
preference :s3_host_alias, :string
|
||||
|
||||
# Default mail headers settings
|
||||
preference :enable_mail_delivery, :boolean, default: false
|
||||
preference :mails_from, :string, default: 'ofn@example.com'
|
||||
preference :mail_bcc, :string, default: 'ofn@example.com'
|
||||
preference :intercept_email, :string, default: nil
|
||||
|
||||
# Default smtp settings
|
||||
preference :override_actionmailer_config, :boolean, default: true
|
||||
preference :mail_host, :string, default: 'localhost'
|
||||
preference :mail_domain, :string, default: 'localhost'
|
||||
preference :mail_port, :integer, default: 25
|
||||
preference :secure_connection_type, :string,
|
||||
default: Core::MailSettings::SECURE_CONNECTION_TYPES[0]
|
||||
preference :mail_auth_type, :string, default: Core::MailSettings::MAIL_AUTH[0]
|
||||
preference :smtp_username, :string
|
||||
preference :smtp_password, :string
|
||||
|
||||
# Embedded Shopfronts
|
||||
preference :enable_embedded_shopfronts, :boolean, default: false
|
||||
preference :embedded_shopfronts_whitelist, :text, default: nil
|
||||
|
||||
# Legal Preferences
|
||||
preference :footer_tos_url, :string, default: "/Terms-of-service.pdf"
|
||||
preference :enterprises_require_tos, :boolean, default: false
|
||||
preference :privacy_policy_url, :string, default: nil
|
||||
preference :cookies_consent_banner_toggle, :boolean, default: false
|
||||
preference :cookies_policy_matomo_section, :boolean, default: false
|
||||
|
||||
# Tax Preferences
|
||||
preference :products_require_tax_category, :boolean, default: false
|
||||
preference :shipping_tax_rate, :decimal, default: 0
|
||||
|
||||
# Monitoring
|
||||
preference :last_job_queue_heartbeat_at, :string, default: nil
|
||||
|
||||
# External services
|
||||
preference :bugherd_api_key, :string, default: nil
|
||||
preference :matomo_url, :string, default: nil
|
||||
preference :matomo_site_id, :string, default: nil
|
||||
preference :matomo_tag_manager_url, :string, default: nil
|
||||
|
||||
# Invoices & Receipts
|
||||
preference :enable_invoices?, :boolean, default: true
|
||||
preference :invoice_style2?, :boolean, default: false
|
||||
preference :enable_receipt_printing?, :boolean, default: false
|
||||
|
||||
# Stripe Connect
|
||||
preference :stripe_connect_enabled, :boolean, default: false
|
||||
|
||||
# Number localization
|
||||
preference :enable_localized_number?, :boolean, default: false
|
||||
|
||||
# Enable cache
|
||||
preference :enable_products_cache?, :boolean,
|
||||
default: (Rails.env.production? || Rails.env.staging?)
|
||||
end
|
||||
end
|
||||
@@ -1,44 +0,0 @@
|
||||
Spree::AppConfiguration.class_eval do
|
||||
# This file decorates the existing preferences file defined by Spree.
|
||||
# It allows us to add our own global configuration variables, which
|
||||
# we can allow to be modified in the UI by adding appropriate form
|
||||
# elements to existing or new configuration pages.
|
||||
|
||||
# Embedded Shopfronts
|
||||
preference :enable_embedded_shopfronts, :boolean, default: false
|
||||
preference :embedded_shopfronts_whitelist, :text, default: nil
|
||||
|
||||
# Legal Preferences
|
||||
preference :footer_tos_url, :string, default: "/Terms-of-service.pdf"
|
||||
preference :enterprises_require_tos, :boolean, default: false
|
||||
preference :privacy_policy_url, :string, default: nil
|
||||
preference :cookies_consent_banner_toggle, :boolean, default: false
|
||||
preference :cookies_policy_matomo_section, :boolean, default: false
|
||||
|
||||
# Tax Preferences
|
||||
preference :products_require_tax_category, :boolean, default: false
|
||||
preference :shipping_tax_rate, :decimal, default: 0
|
||||
|
||||
# Monitoring
|
||||
preference :last_job_queue_heartbeat_at, :string, default: nil
|
||||
|
||||
# External services
|
||||
preference :bugherd_api_key, :string, default: nil
|
||||
preference :matomo_url, :string, default: nil
|
||||
preference :matomo_site_id, :string, default: nil
|
||||
preference :matomo_tag_manager_url, :string, default: nil
|
||||
|
||||
# Invoices & Receipts
|
||||
preference :enable_invoices?, :boolean, default: true
|
||||
preference :invoice_style2?, :boolean, default: false
|
||||
preference :enable_receipt_printing?, :boolean, default: false
|
||||
|
||||
# Stripe Connect
|
||||
preference :stripe_connect_enabled, :boolean, default: false
|
||||
|
||||
# Number localization
|
||||
preference :enable_localized_number?, :boolean, default: false
|
||||
|
||||
# Enable cache
|
||||
preference :enable_products_cache?, :boolean, default: (Rails.env.production? || Rails.env.staging?)
|
||||
end
|
||||
42
app/models/spree/preference.rb
Normal file
42
app/models/spree/preference.rb
Normal file
@@ -0,0 +1,42 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Preference < ActiveRecord::Base
|
||||
serialize :value
|
||||
|
||||
validates :key, presence: true
|
||||
validates :value_type, presence: true
|
||||
|
||||
scope :valid, -> {
|
||||
where(Spree::Preference.arel_table[:key].not_eq(nil)).
|
||||
where(Spree::Preference.arel_table[:value_type].not_eq(nil))
|
||||
}
|
||||
|
||||
# The type conversions here should match
|
||||
# the ones in spree::preferences::preferrable#convert_preference_value
|
||||
def value
|
||||
if self[:value_type].present?
|
||||
case self[:value_type].to_sym
|
||||
when :string, :text
|
||||
self[:value].to_s
|
||||
when :password
|
||||
self[:value].to_s
|
||||
when :decimal
|
||||
BigDecimal(self[:value].to_s).round(2, BigDecimal::ROUND_HALF_UP)
|
||||
when :integer
|
||||
self[:value].to_i
|
||||
when :boolean
|
||||
!(self[:value].to_s =~ /^[t|1]/i).nil?
|
||||
else
|
||||
self[:value].is_a?(String) ? YAML.safe_load(self[:value]) : self[:value]
|
||||
end
|
||||
else
|
||||
self[:value]
|
||||
end
|
||||
end
|
||||
|
||||
def raw_value
|
||||
self[:value]
|
||||
end
|
||||
end
|
||||
end
|
||||
74
app/models/spree/preferences/configuration.rb
Normal file
74
app/models/spree/preferences/configuration.rb
Normal file
@@ -0,0 +1,74 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# This takes the preferrable methods and adds some
|
||||
# syntatic sugar to access the preferences
|
||||
#
|
||||
# class App < Configuration
|
||||
# preference :color, :string
|
||||
# end
|
||||
#
|
||||
# a = App.new
|
||||
#
|
||||
# setters:
|
||||
# a.color = :blue
|
||||
# a[:color] = :blue
|
||||
# a.set :color = :blue
|
||||
# a.preferred_color = :blue
|
||||
#
|
||||
# getters:
|
||||
# a.color
|
||||
# a[:color]
|
||||
# a.get :color
|
||||
# a.preferred_color
|
||||
#
|
||||
#
|
||||
module Spree
|
||||
module Preferences
|
||||
class Configuration
|
||||
include Spree::Preferences::Preferable
|
||||
|
||||
def configure
|
||||
yield(self) if block_given?
|
||||
end
|
||||
|
||||
def preference_cache_key(name)
|
||||
[ENV['RAILS_CACHE_ID'], self.class.name, name].flatten.join('::').underscore
|
||||
end
|
||||
|
||||
def reset
|
||||
preferences.each do |name, _value|
|
||||
set_preference name, preference_default(name)
|
||||
end
|
||||
end
|
||||
|
||||
alias :[] :get_preference
|
||||
alias :[]= :set_preference
|
||||
|
||||
alias :get :get_preference
|
||||
|
||||
def set(*args)
|
||||
options = args.extract_options!
|
||||
options.each do |name, value|
|
||||
set_preference name, value
|
||||
end
|
||||
|
||||
return unless args.size == 2
|
||||
|
||||
set_preference args[0], args[1]
|
||||
end
|
||||
|
||||
def method_missing(method, *args)
|
||||
name = method.to_s.gsub('=', '')
|
||||
if has_preference? name
|
||||
if method.to_s =~ /=$/
|
||||
set_preference(name, args.first)
|
||||
else
|
||||
get_preference name
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
138
app/models/spree/preferences/preferable.rb
Normal file
138
app/models/spree/preferences/preferable.rb
Normal file
@@ -0,0 +1,138 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# The preference_cache_key is used to determine if the preference
|
||||
# can be set. The default behavior is to return nil if there is no
|
||||
# id value. On ActiveRecords, new objects will have their preferences
|
||||
# saved to a pending hash until it is persisted.
|
||||
#
|
||||
# class_attributes are inheritied unless you reassign them in
|
||||
# the subclass, so when you inherit a Preferable class, the
|
||||
# inherited hook will assign a new hash for the subclass definitions
|
||||
# and copy all the definitions allowing the subclass to add
|
||||
# additional defintions without affecting the base
|
||||
module Spree
|
||||
module Preferences
|
||||
module Preferable
|
||||
def self.included(base)
|
||||
base.class_eval do
|
||||
extend Spree::Preferences::PreferableClassMethods
|
||||
|
||||
if respond_to?(:after_create)
|
||||
after_create do |obj|
|
||||
obj.save_pending_preferences
|
||||
end
|
||||
end
|
||||
|
||||
if respond_to?(:after_destroy)
|
||||
after_destroy do |obj|
|
||||
obj.clear_preferences
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_preference(name)
|
||||
has_preference! name
|
||||
__send__ self.class.preference_getter_method(name)
|
||||
end
|
||||
alias :preferred :get_preference
|
||||
alias :prefers? :get_preference
|
||||
|
||||
def set_preference(name, value)
|
||||
has_preference! name
|
||||
__send__ self.class.preference_setter_method(name), value
|
||||
end
|
||||
|
||||
def preference_type(name)
|
||||
has_preference! name
|
||||
__send__ self.class.preference_type_getter_method(name)
|
||||
end
|
||||
|
||||
def preference_default(name)
|
||||
has_preference! name
|
||||
__send__ self.class.preference_default_getter_method(name)
|
||||
end
|
||||
|
||||
def preference_description(name)
|
||||
has_preference! name
|
||||
__send__ self.class.preference_description_getter_method(name)
|
||||
end
|
||||
|
||||
def has_preference!(name)
|
||||
raise NoMethodError, "#{name} preference not defined" unless has_preference? name
|
||||
end
|
||||
|
||||
def has_preference?(name)
|
||||
respond_to? self.class.preference_getter_method(name)
|
||||
end
|
||||
|
||||
def preferences
|
||||
prefs = {}
|
||||
methods.grep(/^prefers_.*\?$/).each do |pref_method|
|
||||
prefs[pref_method.to_s.gsub(/prefers_|\?/, '').to_sym] = __send__(pref_method)
|
||||
end
|
||||
prefs
|
||||
end
|
||||
|
||||
def preference_cache_key(name)
|
||||
return unless id
|
||||
|
||||
[ENV["RAILS_CACHE_ID"], self.class.name, name, id].join('::').underscore
|
||||
end
|
||||
|
||||
def save_pending_preferences
|
||||
return unless @pending_preferences
|
||||
|
||||
@pending_preferences.each do |name, value|
|
||||
set_preference(name, value)
|
||||
end
|
||||
end
|
||||
|
||||
def clear_preferences
|
||||
preferences.keys.each { |pref| preference_store.delete preference_cache_key(pref) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def add_pending_preference(name, value)
|
||||
@pending_preferences ||= {}
|
||||
@pending_preferences[name] = value
|
||||
end
|
||||
|
||||
def get_pending_preference(name)
|
||||
return unless @pending_preferences
|
||||
|
||||
@pending_preferences[name]
|
||||
end
|
||||
|
||||
def convert_preference_value(value, type)
|
||||
case type
|
||||
when :string, :text
|
||||
value.to_s
|
||||
when :password
|
||||
value.to_s
|
||||
when :decimal
|
||||
BigDecimal(value.to_s).round(2, BigDecimal::ROUND_HALF_UP)
|
||||
when :integer
|
||||
value.to_i
|
||||
when :boolean
|
||||
if value.is_a?(FalseClass) ||
|
||||
value.nil? ||
|
||||
value == 0 ||
|
||||
value =~ /^(f|false|0)$/i ||
|
||||
(value.respond_to?(:empty?) && value.empty?)
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
def preference_store
|
||||
Spree::Preferences::Store.instance
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
101
app/models/spree/preferences/preferable_class_methods.rb
Normal file
101
app/models/spree/preferences/preferable_class_methods.rb
Normal file
@@ -0,0 +1,101 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
module Preferences
|
||||
module PreferableClassMethods
|
||||
def preference(name, type, *args)
|
||||
options = args.extract_options!
|
||||
options.assert_valid_keys(:default, :description)
|
||||
default = options[:default]
|
||||
description = options[:description] || name
|
||||
|
||||
# cache_key will be nil for new objects, then if we check if there
|
||||
# is a pending preference before going to default
|
||||
define_method preference_getter_method(name) do
|
||||
# perference_cache_key will only be nil/false for new records
|
||||
#
|
||||
if preference_cache_key(name)
|
||||
preference_store.get(preference_cache_key(name), default)
|
||||
else
|
||||
get_pending_preference(name) || default
|
||||
end
|
||||
end
|
||||
alias_method prefers_getter_method(name), preference_getter_method(name)
|
||||
|
||||
define_method preference_setter_method(name) do |value|
|
||||
value = convert_preference_value(value, type)
|
||||
if preference_cache_key(name)
|
||||
preference_store.set preference_cache_key(name), value, type
|
||||
else
|
||||
add_pending_preference(name, value)
|
||||
end
|
||||
end
|
||||
alias_method prefers_setter_method(name), preference_setter_method(name)
|
||||
|
||||
define_method preference_default_getter_method(name) do
|
||||
default
|
||||
end
|
||||
|
||||
define_method preference_type_getter_method(name) do
|
||||
type
|
||||
end
|
||||
|
||||
define_method preference_description_getter_method(name) do
|
||||
description
|
||||
end
|
||||
end
|
||||
|
||||
def remove_preference(name)
|
||||
if method_defined? preference_getter_method(name)
|
||||
remove_method preference_getter_method(name)
|
||||
end
|
||||
if method_defined? preference_setter_method(name)
|
||||
remove_method preference_setter_method(name)
|
||||
end
|
||||
if method_defined? prefers_getter_method(name)
|
||||
remove_method prefers_getter_method(name)
|
||||
end
|
||||
if method_defined? prefers_setter_method(name)
|
||||
remove_method prefers_setter_method(name)
|
||||
end
|
||||
if method_defined? preference_default_getter_method(name)
|
||||
remove_method preference_default_getter_method(name)
|
||||
end
|
||||
if method_defined? preference_type_getter_method(name)
|
||||
remove_method preference_type_getter_method(name)
|
||||
end
|
||||
if method_defined? preference_description_getter_method(name)
|
||||
remove_method preference_description_getter_method(name)
|
||||
end
|
||||
end
|
||||
|
||||
def preference_getter_method(name)
|
||||
"preferred_#{name}".to_sym
|
||||
end
|
||||
|
||||
def preference_setter_method(name)
|
||||
"preferred_#{name}=".to_sym
|
||||
end
|
||||
|
||||
def prefers_getter_method(name)
|
||||
"prefers_#{name}?".to_sym
|
||||
end
|
||||
|
||||
def prefers_setter_method(name)
|
||||
"prefers_#{name}=".to_sym
|
||||
end
|
||||
|
||||
def preference_default_getter_method(name)
|
||||
"preferred_#{name}_default".to_sym
|
||||
end
|
||||
|
||||
def preference_type_getter_method(name)
|
||||
"preferred_#{name}_type".to_sym
|
||||
end
|
||||
|
||||
def preference_description_getter_method(name)
|
||||
"preferred_#{name}_description".to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
99
app/models/spree/preferences/store.rb
Normal file
99
app/models/spree/preferences/store.rb
Normal file
@@ -0,0 +1,99 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Use singleton class Spree::Preferences::Store.instance to access
|
||||
#
|
||||
# StoreInstance has a persistence flag that is on by default,
|
||||
# but we disable database persistence in testing to speed up tests
|
||||
#
|
||||
|
||||
require 'singleton'
|
||||
|
||||
module Spree
|
||||
module Preferences
|
||||
class StoreInstance
|
||||
attr_accessor :persistence
|
||||
|
||||
def initialize
|
||||
@cache = Rails.cache
|
||||
@persistence = true
|
||||
end
|
||||
|
||||
def set(key, value, type)
|
||||
@cache.write(key, value)
|
||||
persist(key, value, type)
|
||||
end
|
||||
|
||||
def exist?(key)
|
||||
@cache.exist?(key) ||
|
||||
should_persist? && Spree::Preference.where(key: key).exists?
|
||||
end
|
||||
|
||||
def get(key, fallback = nil)
|
||||
# return the retrieved value, if it's in the cache
|
||||
# use unless nil? incase the value is actually boolean false
|
||||
#
|
||||
unless (val = @cache.read(key)).nil?
|
||||
return val
|
||||
end
|
||||
|
||||
if should_persist?
|
||||
# If it's not in the cache, maybe it's in the database, but
|
||||
# has been cleared from the cache
|
||||
|
||||
# does it exist in the database?
|
||||
if Spree::Preference.table_exists? && preference = Spree::Preference.find_by(key: key)
|
||||
# it does exist, so let's put it back into the cache
|
||||
@cache.write(preference.key, preference.value)
|
||||
|
||||
# and return the value
|
||||
return preference.value
|
||||
end
|
||||
end
|
||||
|
||||
unless fallback.nil?
|
||||
# cache fallback so we won't hit the db above on
|
||||
# subsequent queries for the same key
|
||||
#
|
||||
@cache.write(key, fallback)
|
||||
end
|
||||
|
||||
fallback
|
||||
end
|
||||
|
||||
def delete(key)
|
||||
@cache.delete(key)
|
||||
destroy(key)
|
||||
end
|
||||
|
||||
def clear_cache
|
||||
@cache.clear
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def persist(cache_key, value, type)
|
||||
return unless should_persist?
|
||||
|
||||
preference = Spree::Preference.where(key: cache_key).first_or_initialize
|
||||
preference.value = value
|
||||
preference.value_type = type
|
||||
preference.save
|
||||
end
|
||||
|
||||
def destroy(cache_key)
|
||||
return unless should_persist?
|
||||
|
||||
preference = Spree::Preference.find_by(key: cache_key)
|
||||
preference&.destroy
|
||||
end
|
||||
|
||||
def should_persist?
|
||||
@persistence && Spree::Preference.connected? && Spree::Preference.table_exists?
|
||||
end
|
||||
end
|
||||
|
||||
class Store < StoreInstance
|
||||
include Singleton
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -16,10 +16,6 @@
|
||||
%div{class: "field"}
|
||||
= f.label :lastname, Spree.t(:last_name) + ':'
|
||||
= f.text_field :lastname, class: 'fullwidth'
|
||||
- if Spree::Config[:company]
|
||||
%div{class: "field"}
|
||||
= f.label :company, Spree.t(:company) + ':'
|
||||
= f.text_field :company, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :address1, Spree.t(:street_address) + ':'
|
||||
= f.text_field :address1, class: 'fullwidth'
|
||||
|
||||
@@ -37,11 +37,7 @@ module Spree
|
||||
def title
|
||||
title_string = @title.presence || accurate_title
|
||||
if title_string.present?
|
||||
if Spree::Config[:always_put_site_name_in_title]
|
||||
[title_string, default_title].join(' - ')
|
||||
else
|
||||
title_string
|
||||
end
|
||||
[title_string, default_title].join(' - ')
|
||||
else
|
||||
default_title
|
||||
end
|
||||
|
||||
@@ -12,19 +12,19 @@ describe "General Settings" do
|
||||
context "visiting general settings (admin)" do
|
||||
it "should have the right content" do
|
||||
expect(page).to have_content("General Settings")
|
||||
expect(find("#site_name").value).to eq("Spree Demo Site")
|
||||
expect(find("#site_url").value).to eq("demo.spreecommerce.com")
|
||||
expect(find("#site_name").value).to eq("OFN Demo Site")
|
||||
expect(find("#site_url").value).to eq("demo.openfoodnetwork.org")
|
||||
end
|
||||
end
|
||||
|
||||
context "editing general settings (admin)" do
|
||||
it "should be able to update the site name" do
|
||||
fill_in "site_name", with: "Spree Demo Site99"
|
||||
fill_in "site_name", with: "OFN Demo Site99"
|
||||
click_button "Update"
|
||||
|
||||
assert_successful_update_message(:general_settings)
|
||||
|
||||
expect(find("#site_name").value).to eq("Spree Demo Site99")
|
||||
expect(find("#site_name").value).to eq("OFN Demo Site99")
|
||||
end
|
||||
|
||||
def assert_successful_update_message(resource)
|
||||
|
||||
17
spec/models/spree/app_configuration_spec.rb
Normal file
17
spec/models/spree/app_configuration_spec.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::AppConfiguration do
|
||||
let(:prefs) { Rails.application.config.spree.preferences }
|
||||
|
||||
it "should be available from the environment" do
|
||||
prefs.site_name = "TEST SITE NAME"
|
||||
expect(prefs.site_name).to eq "TEST SITE NAME"
|
||||
end
|
||||
|
||||
it "should be available as Spree::Config for legacy access" do
|
||||
Spree::Config.site_name = "Spree::Config TEST SITE NAME"
|
||||
expect(Spree::Config.site_name).to eq "Spree::Config TEST SITE NAME"
|
||||
end
|
||||
end
|
||||
97
spec/models/spree/preference_spec.rb
Normal file
97
spec/models/spree/preference_spec.rb
Normal file
@@ -0,0 +1,97 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Preference do
|
||||
it "should require a key" do
|
||||
@preference = Spree::Preference.new
|
||||
@preference.key = :test
|
||||
@preference.value_type = :boolean
|
||||
@preference.value = true
|
||||
expect(@preference).to be_valid
|
||||
end
|
||||
|
||||
describe "type coversion for values" do
|
||||
def round_trip_preference(key, value, value_type)
|
||||
p = Spree::Preference.new
|
||||
p.value = value
|
||||
p.value_type = value_type
|
||||
p.key = key
|
||||
p.save
|
||||
|
||||
Spree::Preference.find_by(key: key)
|
||||
end
|
||||
|
||||
it ":boolean" do
|
||||
value_type = :boolean
|
||||
value = true
|
||||
key = "boolean_key"
|
||||
pref = round_trip_preference(key, value, value_type)
|
||||
expect(pref.value).to eq value
|
||||
expect(pref.value_type).to eq value_type.to_s
|
||||
end
|
||||
|
||||
it "false :boolean" do
|
||||
value_type = :boolean
|
||||
value = false
|
||||
key = "boolean_key"
|
||||
pref = round_trip_preference(key, value, value_type)
|
||||
expect(pref.value).to eq value
|
||||
expect(pref.value_type).to eq value_type.to_s
|
||||
end
|
||||
|
||||
it ":integer" do
|
||||
value_type = :integer
|
||||
value = 10
|
||||
key = "integer_key"
|
||||
pref = round_trip_preference(key, value, value_type)
|
||||
expect(pref.value).to eq value
|
||||
expect(pref.value_type).to eq value_type.to_s
|
||||
end
|
||||
|
||||
it ":decimal" do
|
||||
value_type = :decimal
|
||||
value = 1.5
|
||||
key = "decimal_key"
|
||||
pref = round_trip_preference(key, value, value_type)
|
||||
expect(pref.value).to eq value
|
||||
expect(pref.value_type).to eq value_type.to_s
|
||||
end
|
||||
|
||||
it ":string" do
|
||||
value_type = :string
|
||||
value = "This is a string"
|
||||
key = "string_key"
|
||||
pref = round_trip_preference(key, value, value_type)
|
||||
expect(pref.value).to eq value
|
||||
expect(pref.value_type).to eq value_type.to_s
|
||||
end
|
||||
|
||||
it ":text" do
|
||||
value_type = :text
|
||||
value = "This is a string stored as text"
|
||||
key = "text_key"
|
||||
pref = round_trip_preference(key, value, value_type)
|
||||
expect(pref.value).to eq value
|
||||
expect(pref.value_type).to eq value_type.to_s
|
||||
end
|
||||
|
||||
it ":password" do
|
||||
value_type = :password
|
||||
value = "This is a password"
|
||||
key = "password_key"
|
||||
pref = round_trip_preference(key, value, value_type)
|
||||
expect(pref.value).to eq value
|
||||
expect(pref.value_type).to eq value_type.to_s
|
||||
end
|
||||
|
||||
it ":any" do
|
||||
value_type = :any
|
||||
value = [1, 2]
|
||||
key = "any_key"
|
||||
pref = round_trip_preference(key, value, value_type)
|
||||
expect(pref.value).to eq value
|
||||
expect(pref.value_type).to eq value_type.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
27
spec/models/spree/preferences/configuration_spec.rb
Normal file
27
spec/models/spree/preferences/configuration_spec.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Preferences::Configuration do
|
||||
before :all do
|
||||
class AppConfig < Spree::Preferences::Configuration
|
||||
preference :color, :string, default: :blue
|
||||
end
|
||||
@config = AppConfig.new
|
||||
end
|
||||
|
||||
it "has named methods to access preferences" do
|
||||
@config.color = 'orange'
|
||||
expect(@config.color).to eq 'orange'
|
||||
end
|
||||
|
||||
it "uses [ ] to access preferences" do
|
||||
@config[:color] = 'red'
|
||||
expect(@config[:color]).to eq 'red'
|
||||
end
|
||||
|
||||
it "uses set/get to access preferences" do
|
||||
@config.set :color, 'green'
|
||||
expect(@config.get(:color)).to eq 'green'
|
||||
end
|
||||
end
|
||||
326
spec/models/spree/preferences/preferable_spec.rb
Normal file
326
spec/models/spree/preferences/preferable_spec.rb
Normal file
@@ -0,0 +1,326 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Preferences::Preferable do
|
||||
before :all do
|
||||
class A
|
||||
include Spree::Preferences::Preferable
|
||||
attr_reader :id
|
||||
|
||||
def initialize
|
||||
@id = rand(999)
|
||||
end
|
||||
|
||||
preference :color, :string, default: 'green', description: "My Favorite Color"
|
||||
end
|
||||
|
||||
class B < A
|
||||
preference :flavor, :string
|
||||
end
|
||||
end
|
||||
|
||||
before :each do
|
||||
@a = A.new
|
||||
allow(@a).to receive_messages(persisted?: true)
|
||||
@b = B.new
|
||||
allow(@b).to receive_messages(persisted?: true)
|
||||
|
||||
# ensure we're persisting as that is the default
|
||||
#
|
||||
store = Spree::Preferences::Store.instance
|
||||
store.persistence = true
|
||||
end
|
||||
|
||||
describe "preference definitions" do
|
||||
it "parent should not see child definitions" do
|
||||
expect(@a.has_preference?(:color)).to be_truthy
|
||||
expect(@a.has_preference?(:flavor)).not_to be_truthy
|
||||
end
|
||||
|
||||
it "child should have parent and own definitions" do
|
||||
expect(@b.has_preference?(:color)).to be_truthy
|
||||
expect(@b.has_preference?(:flavor)).to be_truthy
|
||||
end
|
||||
|
||||
it "instances have defaults" do
|
||||
expect(@a.preferred_color).to eq 'green'
|
||||
expect(@b.preferred_color).to eq 'green'
|
||||
expect(@b.preferred_flavor).to be_nil
|
||||
end
|
||||
|
||||
it "can be asked if it has a preference definition" do
|
||||
expect(@a.has_preference?(:color)).to be_truthy
|
||||
expect(@a.has_preference?(:bad)).to be_falsy
|
||||
end
|
||||
|
||||
it "can be asked and raises" do
|
||||
expect {
|
||||
@a.has_preference! :flavor
|
||||
}.to raise_error(NoMethodError, "flavor preference not defined")
|
||||
end
|
||||
|
||||
it "has a type" do
|
||||
expect(@a.preferred_color_type).to eq :string
|
||||
expect(@a.preference_type(:color)).to eq :string
|
||||
end
|
||||
|
||||
it "has a default" do
|
||||
expect(@a.preferred_color_default).to eq 'green'
|
||||
expect(@a.preference_default(:color)).to eq 'green'
|
||||
end
|
||||
|
||||
it "has a description" do
|
||||
expect(@a.preferred_color_description).to eq "My Favorite Color"
|
||||
expect(@a.preference_description(:color)).to eq "My Favorite Color"
|
||||
end
|
||||
|
||||
it "raises if not defined" do
|
||||
expect {
|
||||
@a.get_preference :flavor
|
||||
}.to raise_error(NoMethodError, "flavor preference not defined")
|
||||
end
|
||||
end
|
||||
|
||||
describe "preference access" do
|
||||
it "handles ghost methods for preferences" do
|
||||
@a.preferred_color = 'blue'
|
||||
expect(@a.preferred_color).to eq 'blue'
|
||||
|
||||
@a.prefers_color = 'green'
|
||||
expect(@a.prefers_color?).to eq 'green'
|
||||
end
|
||||
|
||||
it "has genric readers" do
|
||||
@a.preferred_color = 'red'
|
||||
expect(@a.prefers?(:color)).to eq 'red'
|
||||
expect(@a.preferred(:color)).to eq 'red'
|
||||
end
|
||||
|
||||
it "parent and child instances have their own prefs" do
|
||||
@a.preferred_color = 'red'
|
||||
@b.preferred_color = 'blue'
|
||||
|
||||
expect(@a.preferred_color).to eq 'red'
|
||||
expect(@b.preferred_color).to eq 'blue'
|
||||
end
|
||||
|
||||
it "raises when preference not defined" do
|
||||
expect {
|
||||
@a.set_preference(:bad, :bone)
|
||||
}.to raise_exception(NoMethodError, "bad preference not defined")
|
||||
end
|
||||
|
||||
it "builds a hash of preferences" do
|
||||
@b.preferred_flavor = :strawberry
|
||||
expect(@b.preferences[:flavor]).to eq 'strawberry'
|
||||
expect(@b.preferences[:color]).to eq 'green' # default from A
|
||||
end
|
||||
|
||||
context "database fallback" do
|
||||
before do
|
||||
@a.instance_variable_set("@pending_preferences", {})
|
||||
end
|
||||
|
||||
it "retrieves a preference from the database before falling back to default" do
|
||||
preference = double(value: "chatreuse", key: 'a/color/123')
|
||||
expect(Spree::Preference).to receive(:find_by).and_return(preference)
|
||||
expect(@a.preferred_color).to eq 'chatreuse'
|
||||
end
|
||||
|
||||
it "defaults if no database key exists" do
|
||||
expect(Spree::Preference).to receive(:find_by).and_return(nil)
|
||||
expect(@a.preferred_color).to eq 'green'
|
||||
end
|
||||
end
|
||||
|
||||
context "converts integer preferences to integer values" do
|
||||
before do
|
||||
A.preference :is_integer, :integer
|
||||
end
|
||||
|
||||
it "with strings" do
|
||||
@a.set_preference(:is_integer, '3')
|
||||
expect(@a.preferences[:is_integer]).to eq 3
|
||||
|
||||
@a.set_preference(:is_integer, '')
|
||||
expect(@a.preferences[:is_integer]).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context "converts decimal preferences to BigDecimal values" do
|
||||
before do
|
||||
A.preference :if_decimal, :decimal
|
||||
end
|
||||
|
||||
it "returns a BigDecimal" do
|
||||
@a.set_preference(:if_decimal, 3.3)
|
||||
expect(@a.preferences[:if_decimal].class).to eq BigDecimal
|
||||
end
|
||||
|
||||
it "with strings" do
|
||||
@a.set_preference(:if_decimal, '3.3')
|
||||
expect(@a.preferences[:if_decimal]).to eq 3.3
|
||||
|
||||
@a.set_preference(:if_decimal, '')
|
||||
expect(@a.preferences[:if_decimal]).to eq 0.0
|
||||
end
|
||||
end
|
||||
|
||||
context "converts boolean preferences to boolean values" do
|
||||
before do
|
||||
A.preference :is_boolean, :boolean, default: true
|
||||
end
|
||||
|
||||
it "with strings" do
|
||||
@a.set_preference(:is_boolean, '0')
|
||||
expect(@a.preferences[:is_boolean]).to be_falsy
|
||||
@a.set_preference(:is_boolean, 'f')
|
||||
expect(@a.preferences[:is_boolean]).to be_falsy
|
||||
@a.set_preference(:is_boolean, 't')
|
||||
expect(@a.preferences[:is_boolean]).to be_truthy
|
||||
end
|
||||
|
||||
it "with integers" do
|
||||
@a.set_preference(:is_boolean, 0)
|
||||
expect(@a.preferences[:is_boolean]).to be_falsy
|
||||
@a.set_preference(:is_boolean, 1)
|
||||
expect(@a.preferences[:is_boolean]).to be_truthy
|
||||
end
|
||||
|
||||
it "with an empty string" do
|
||||
@a.set_preference(:is_boolean, '')
|
||||
expect(@a.preferences[:is_boolean]).to be_falsy
|
||||
end
|
||||
|
||||
it "with an empty hash" do
|
||||
@a.set_preference(:is_boolean, [])
|
||||
expect(@a.preferences[:is_boolean]).to be_falsy
|
||||
end
|
||||
end
|
||||
|
||||
context "converts any preferences to any values" do
|
||||
before do
|
||||
A.preference :product_ids, :any, default: []
|
||||
A.preference :product_attributes, :any, default: {}
|
||||
end
|
||||
|
||||
it "with array" do
|
||||
expect(@a.preferences[:product_ids]).to eq []
|
||||
@a.set_preference(:product_ids, [1, 2])
|
||||
expect(@a.preferences[:product_ids]).to eq [1, 2]
|
||||
end
|
||||
|
||||
it "with hash" do
|
||||
expect(@a.preferences[:product_attributes]).to eq({})
|
||||
@a.set_preference(:product_attributes, { id: 1, name: 2 })
|
||||
attributes_hash = { id: 1, name: 2 }
|
||||
expect(@a.preferences[:product_attributes]).to eq attributes_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "persisted preferables" do
|
||||
before(:all) do
|
||||
class CreatePrefTest < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :pref_tests do |t|
|
||||
t.string :col
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :pref_tests
|
||||
end
|
||||
end
|
||||
|
||||
@migration_verbosity = ActiveRecord::Migration.verbose
|
||||
ActiveRecord::Migration.verbose = false
|
||||
CreatePrefTest.migrate(:up)
|
||||
|
||||
class PrefTest < ActiveRecord::Base
|
||||
preference :pref_test_pref, :string, default: 'abc'
|
||||
preference :pref_test_any, :any, default: []
|
||||
end
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
CreatePrefTest.migrate(:down)
|
||||
ActiveRecord::Migration.verbose = @migration_verbosity
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
@pt = PrefTest.create
|
||||
end
|
||||
|
||||
describe "pending preferences for new activerecord objects" do
|
||||
it "saves preferences after record is saved" do
|
||||
pr = PrefTest.new
|
||||
pr.set_preference(:pref_test_pref, 'XXX')
|
||||
expect(pr.get_preference(:pref_test_pref)).to eq 'XXX'
|
||||
pr.save!
|
||||
expect(pr.get_preference(:pref_test_pref)).to eq 'XXX'
|
||||
end
|
||||
|
||||
it "saves preferences for serialized object" do
|
||||
pr = PrefTest.new
|
||||
pr.set_preference(:pref_test_any, [1, 2])
|
||||
expect(pr.get_preference(:pref_test_any)).to eq [1, 2]
|
||||
pr.save!
|
||||
expect(pr.get_preference(:pref_test_any)).to eq [1, 2]
|
||||
end
|
||||
end
|
||||
|
||||
describe "requires a valid id" do
|
||||
it "for cache_key" do
|
||||
pref_test = PrefTest.new
|
||||
expect(pref_test.preference_cache_key(:pref_test_pref)).to be_nil
|
||||
|
||||
pref_test.save
|
||||
expect(pref_test.preference_cache_key(:pref_test_pref)).to_not be_nil
|
||||
end
|
||||
|
||||
it "but returns default values" do
|
||||
pref_test = PrefTest.new
|
||||
expect(pref_test.get_preference(:pref_test_pref)).to eq 'abc'
|
||||
end
|
||||
|
||||
it "adds prefs in a pending hash until after_create" do
|
||||
pref_test = PrefTest.new
|
||||
expect(pref_test).to receive(:add_pending_preference).with(:pref_test_pref, 'XXX')
|
||||
pref_test.set_preference(:pref_test_pref, 'XXX')
|
||||
end
|
||||
end
|
||||
|
||||
it "clear preferences" do
|
||||
@pt.set_preference(:pref_test_pref, 'xyz')
|
||||
expect(@pt.preferred_pref_test_pref).to eq 'xyz'
|
||||
@pt.clear_preferences
|
||||
expect(@pt.preferred_pref_test_pref).to eq 'abc'
|
||||
end
|
||||
|
||||
it "clear preferences when record is deleted" do
|
||||
@pt.save!
|
||||
@pt.preferred_pref_test_pref = 'lmn'
|
||||
@pt.save!
|
||||
@pt.destroy
|
||||
@pt1 = PrefTest.new(col: 'aaaa')
|
||||
@pt1.id = @pt.id
|
||||
@pt1.save!
|
||||
expect(@pt1.get_preference(:pref_test_pref)).to_not eq 'lmn'
|
||||
expect(@pt1.get_preference(:pref_test_pref)).to eq 'abc'
|
||||
end
|
||||
end
|
||||
|
||||
it "builds cache keys" do
|
||||
expect(@a.preference_cache_key(:color)).to match %r{a/color/\d+}
|
||||
end
|
||||
|
||||
it "can add and remove preferences" do
|
||||
A.preference :test_temp, :boolean, default: true
|
||||
expect(@a.preferred_test_temp).to be_truthy
|
||||
A.remove_preference :test_temp
|
||||
expect(@a.has_preference?(:test_temp)).to be_falsy
|
||||
expect(@a.respond_to?(:preferred_test_temp)).to be_falsy
|
||||
end
|
||||
end
|
||||
48
spec/models/spree/preferences/store_spec.rb
Normal file
48
spec/models/spree/preferences/store_spec.rb
Normal file
@@ -0,0 +1,48 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Preferences::Store do
|
||||
before :each do
|
||||
@store = Spree::Preferences::StoreInstance.new
|
||||
end
|
||||
|
||||
it "sets and gets a key" do
|
||||
@store.set :test, 1, :integer
|
||||
expect(@store.exist?(:test)).to be_truthy
|
||||
expect(@store.get(:test)).to eq 1
|
||||
end
|
||||
|
||||
it "can set and get false values when cache return nil" do
|
||||
@store.set :test, false, :boolean
|
||||
expect(@store.get(:test)).to be_falsy
|
||||
end
|
||||
|
||||
it "will return db value when cache is emtpy and cache the db value" do
|
||||
preference = Spree::Preference.where(key: 'test').first_or_initialize
|
||||
preference.value = '123'
|
||||
preference.value_type = 'string'
|
||||
preference.save
|
||||
|
||||
Rails.cache.clear
|
||||
expect(@store.get(:test)).to eq '123'
|
||||
expect(Rails.cache.read(:test)).to eq '123'
|
||||
end
|
||||
|
||||
it "should return and cache fallback value when supplied" do
|
||||
Rails.cache.clear
|
||||
expect(@store.get(:test, false)).to be_falsy
|
||||
expect(Rails.cache.read(:test)).to be_falsy
|
||||
end
|
||||
|
||||
it "should return and cache fallback value when persistence is disabled (i.e. on bootstrap)" do
|
||||
Rails.cache.clear
|
||||
allow(@store).to receive_messages(should_persist?: false)
|
||||
expect(@store.get(:test, true)).to be_truthy
|
||||
expect(Rails.cache.read(:test)).to be_truthy
|
||||
end
|
||||
|
||||
it "should return nil when key can't be found and fallback value is not supplied" do
|
||||
expect(@store.get(:random_key)).to be_nil
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user