Permalink
Browse files

Merge pull request #1211 from interhive/feature-per-site-asset-host

feature: per-site asset host
  • Loading branch information...
did committed Jun 27, 2017
2 parents 8bbe976 + 73f7a41 commit 9138a27b953d6f0dcf720ef049a1ac4fd1f7ba36
@@ -7,7 +7,7 @@ class SiteEntity < BaseEntity
expose :name, :handle, :seo_title, :meta_keywords, :meta_description,
:robots_txt, :cache_enabled, :private_access
expose :locales, :domains, :url_redirections
expose :locales, :domains, :asset_host, :url_redirections
expose :memberships, using: MembershipEntity
@@ -4,7 +4,7 @@ module Forms
class SiteForm < BaseForm
attrs :name, :handle, :robots_txt, :locales, :domains, :url_redirections, :timezone, :picture, :cache_enabled, :private_access, :password, :metafields_schema, :metafields, :metafields_ui
attrs :name, :handle, :robots_txt, :locales, :domains, :url_redirections, :timezone, :picture, :cache_enabled, :private_access, :password, :metafields_schema, :metafields, :metafields_ui, :asset_host
attrs :seo_title, :meta_keywords, :meta_description, localized: true
# Make sure locales and domains are in arrays.
@@ -44,6 +44,7 @@ def service
optional :metafields_schema
optional :metafields
optional :metafields_ui
optional :asset_host
end
end
put do
@@ -71,6 +71,7 @@ def load_site
optional :metafields_schema
optional :metafields
optional :metafields_ui
optional :asset_host
end
end
post do
@@ -101,6 +102,7 @@ def load_site
optional :password
optional :metafields_schema
optional :metafields
optional :asset_host
end
end
put ':id' do
@@ -12,6 +12,7 @@ module AccessPoints
field :domains, type: Array, default: []
field :redirect_to_first_domain, type: Boolean, default: false
field :redirect_to_https, type: Boolean, default: false
field :asset_host
## indexes ##
index domains: 1
@@ -24,6 +25,7 @@ module AccessPoints
multiline: true
validate :domains_must_be_valid_and_unique
validate :domains_must_not_be_reserved
validate :asset_host_must_be_valid
## callbacks ##
before_validation :prepare_domain_sync
@@ -54,6 +56,10 @@ def domains=(array)
array = [] if array.blank?; super(array.map(&:downcase))
end
def asset_host=(asset_host)
super(asset_host.try(:downcase))
end
protected
def prepare_domain_sync
@@ -76,6 +82,14 @@ def domains_must_be_valid_and_unique
end
end
def asset_host_must_be_valid
return if self.asset_host.blank?
if not asset_host =~ Locomotive::Regexps::ASSET_HOST
self.errors.add(:asset_host, :invalid_domain, value: asset_host)
end
end
def domains_must_not_be_reserved
return if self.domains.empty? || Locomotive.config.reserved_domains.blank?
@@ -46,11 +46,11 @@ def show_developers_documentation?
end
def permitted_attributes
plain = [:name, :handle, :picture, :remove_picture, :seo_title, :meta_keywords, :meta_description, :timezone_name, :robots_txt, :cache_enabled, :redirect_to_first_domain, :redirect_to_https, :private_access, :password, :prefix_default_locale]
plain = [:name, :handle, :picture, :remove_picture, :seo_title, :meta_keywords, :meta_description, :timezone_name, :robots_txt, :asset_host, :cache_enabled, :redirect_to_first_domain, :redirect_to_https, :private_access, :password, :prefix_default_locale]
hash = { domains: [], locales: [], url_redirections: [] }
unless update_advanced?
plain -= [:timezone_name, :robots_txt, :cache_enabled, :prefix_default_locale]
plain -= [:timezone_name, :robots_txt, :cache_enabled, :prefix_default_locale, :asset_host]
hash.delete(:locales)
hash.delete(:url_redirections)
end
@@ -4,6 +4,8 @@
= f.input :domains, as: :array, hint: t(:domains, scope: 'simple_form.hints.locomotive.site', domain: Locomotive.config.host || request.host).html_safe, placeholder: true, collection: f.object.domains, template: :domain, template_url: new_domain_current_site_path(current_site)
= f.input :asset_host, hint: t(:asset_host, scope: 'simple_form.hints.locomotive.site').html_safe
= f.input :redirect_to_first_domain, as: :toggle
= f.input :redirect_to_https, as: :toggle
@@ -96,6 +96,7 @@ en:
meta_description: "Meta description used within the head tag of the page. Required for SEO."
robots_txt: "Content of the <span class='code'>/robots.txt</span> file. Check the following <a href='http://www.w3.org/TR/html4/appendix/notes.html#h-B.4.1.1'>url</a> for more information."
domains: "Add your domains just below. Documentation <a href=\"https://locomotive-v3.readme.io/docs/domains\">here</a> for more information."
asset_host: "Site-specific asset host that overrides engine asset host (ex. \"localhost\", \"asset.dev\", \"https://asset-host.com/\")."
memberships: "You can invite other accounts to edit/manage the site."
cache_enabled: "When enabled, your pages will be cached as long as the content doesn't change. Disabling cache per page is allowed."
redirect_to_first_domain: "When enabled, requests made to any domains listed above will be redirected to the first domain."
@@ -9,5 +9,8 @@ module Regexps
URL_AND_MAILTO = /\A((https?:\/\/\S+)|(ftp:\/\S+)|(mailto:\S+)|\/\S*)\Z/
# e.g. hostname, hostname.com, http(s)://hostname, http(s)://hostname.com/
ASSET_HOST = /\A((https?:\/\/)?)(([a-z\d])([a-z\d-]){0,61}([a-z\d]))(\.([a-z\d])([a-z\d-]){0,61}([a-z\d]))*\/?$/i
end
end
@@ -5,7 +5,7 @@
subject { described_class }
%i(name locales handle domains seo_title meta_keywords
meta_description robots_txt cache_enabled).each do |exposure|
meta_description robots_txt cache_enabled asset_host).each do |exposure|
it { is_expected.to represent(exposure) }
end
@@ -2,14 +2,14 @@
describe Locomotive::API::Forms::SiteForm do
let(:attributes) { { name: 'Acme Corp', handle: 'acme', locales: 'en', domains: 'www.acme.com', seo_title: 'Hi' } }
let(:attributes) { { name: 'Acme Corp', handle: 'acme', locales: 'en', domains: 'www.acme.com', seo_title: 'Hi', asset_host: 'http://asset.dev' } }
let(:form) { described_class.new(attributes) }
describe '#serializable_hash' do
subject { form.serializable_hash }
it { is_expected.to eq('name' => 'Acme Corp', 'handle' => 'acme', 'locales' => ['en'], 'domains' => ['www.acme.com'], 'seo_title' => 'Hi') }
it { is_expected.to eq('name' => 'Acme Corp', 'handle' => 'acme', 'locales' => ['en'], 'domains' => ['www.acme.com'], 'seo_title' => 'Hi', 'asset_host' => 'http://asset.dev') }
context 'localized' do
@@ -3,96 +3,176 @@
describe Locomotive::Concerns::Site::AccessPoints do
let(:domains) { [] }
let(:site) { build(:site, domains: domains) }
let(:asset_host) { nil }
let(:site) { build(:site, domains: domains, asset_host: asset_host) }
describe '#domains=' do
describe 'domains' do
it 'downcases the domains' do
site.domains = ['FIRST.com', 'second.com', 'THIRD.com']
describe '#domains=' do
expect(site.domains).to eq(['first.com', 'second.com', 'third.com'])
it 'downcases the domains' do
site.domains = ['FIRST.com', 'second.com', 'THIRD.com']
expect(site.domains).to eq(['first.com', 'second.com', 'third.com'])
end
end
end
describe '#valid?' do
describe '#valid?' do
subject { site.valid? }
subject { site.valid? }
it { is_expected.to eq true }
it { is_expected.to eq true }
describe 'forbidden domains defined' do
describe 'forbidden domains defined' do
before { allow(Locomotive.config).to receive(:reserved_domains).and_return(['www.locomotiveapp.com', /.+\.acme\.org/]) }
before { allow(Locomotive.config).to receive(:reserved_domains).and_return(['www.locomotiveapp.com', /.+\.acme\.org/]) }
let(:domains) { ['example.fr', 'acme.org'] }
let(:domains) { ['example.fr', 'acme.org'] }
it { is_expected.to eq true }
it { is_expected.to eq true }
context 'setting a forbidden domain name' do
context 'setting a forbidden domain name' do
let(:domains) { ['example.fr', 'www.locomotiveapp.com', 'staging.acme.org'] }
let(:domains) { ['example.fr', 'www.locomotiveapp.com', 'staging.acme.org'] }
it 'adds errors for each invalid domain' do
is_expected.to eq false
expect(site.errors['domains']).to eq(["www.locomotiveapp.com is already taken", "staging.acme.org is already taken"])
end
it 'adds errors for each invalid domain' do
is_expected.to eq false
expect(site.errors['domains']).to eq(["www.locomotiveapp.com is already taken", "staging.acme.org is already taken"])
end
end
end
end
describe 'domain sync' do
describe 'domain sync' do
let!(:listener) { DomainEventListener.new }
after { listener.shutdown }
let!(:listener) { DomainEventListener.new }
after { listener.shutdown }
subject { listener }
subject { listener }
describe 'on saving' do
describe 'on saving' do
before { site.save }
before { site.save }
it 'does not emit an event' do
expect(subject.size).to eq 0
end
it 'does not emit an event' do
expect(subject.size).to eq 0
end
context 'new site' do
context 'new site' do
let(:domains) { ['www.example.com', 'example.com'] }
let(:domains) { ['www.example.com', 'example.com'] }
it 'only tracks new domains' do
expect(subject.added).to eq(['www.example.com', 'example.com'])
expect(subject.removed).to eq([])
end
end
context 'existing site' do
let(:domains) { ['www.boring.org', 'www.awesome.io'] }
before { listener.clear; site.domains = ['www.acme.com', 'www.awesome.io']; site.save; site.reload }
it 'tracks new domains and removed ones' do
expect(subject.added).to eq(['www.acme.com'])
expect(subject.removed).to eq(['www.boring.org'])
end
it 'only tracks new domains' do
expect(subject.added).to eq(['www.example.com', 'example.com'])
expect(subject.removed).to eq([])
end
end
context 'existing site' do
describe 'on destroying' do
let(:domains) { ['www.boring.org', 'www.awesome.io'] }
let(:domains) { ['www.example.com', 'example.com'] }
before { listener.clear; site.domains = ['www.acme.com', 'www.awesome.io']; site.save; site.reload }
before { site.save; listener.clear; site.destroy }
it 'tracks new domains and removed ones' do
expect(subject.added).to eq(['www.acme.com'])
expect(subject.removed).to eq(['www.boring.org'])
it 'tracks removed domains' do
expect(subject.added).to eq([])
expect(subject.removed).to eq(['www.example.com', 'example.com'])
end
end
end
end
describe 'asset_host' do
describe '#asset_host=' do
it 'downcases the asset host' do
site.asset_host = 'ASSET.DEV'
expect(site.asset_host).to eq('asset.dev')
end
end
describe '#valid?' do
subject { site.valid? }
it { is_expected.to eq true }
describe 'on destroying' do
describe 'valid hostname defined' do
let(:domains) { ['www.example.com', 'example.com'] }
let(:asset_host) { 'asset.dev' }
before { site.save; listener.clear; site.destroy }
it { is_expected.to eq true }
end
describe 'valid urls defined' do
let(:asset_host) { 'https://asset.dev' }
it { is_expected.to eq true }
let(:asset_host) { 'https://asset.dev/' }
it { is_expected.to eq true }
end
describe 'invalid hostname or url defined' do
let(:asset_host) { 'asset.d' }
it { is_expected.to eq false }
let(:asset_host) { 'https://asset.d-' }
it { is_expected.to eq false }
context 'setting an invalid hostname' do
let(:asset_host) { 'asset.d' }
it 'adds error to asset_host field' do
is_expected.to eq false
expect(site.errors['asset_host']).to eq(['asset.d is invalid'])
end
end
context 'setting an invalid url' do
let(:asset_host) { 'http://asset.d-' }
it 'adds error to asset_host field' do
is_expected.to eq false
expect(site.errors['asset_host']).to eq(['http://asset.d- is invalid'])
end
end
it 'tracks removed domains' do
expect(subject.added).to eq([])
expect(subject.removed).to eq(['www.example.com', 'example.com'])
end
end
@@ -126,4 +206,4 @@ def shutdown
end
end
end
end
Oops, something went wrong.

0 comments on commit 9138a27

Please sign in to comment.