Browse Source

close #86 Changing root of a domains tree

pull/1/head
Nicolae Claudius 13 years ago
parent
commit
b66fa1681d
  1. 10
      Gemfile
  2. 52
      Gemfile.lock
  3. 8
      app/controllers/domains_controller.rb
  4. 2
      app/models/domain.rb
  5. 0
      app/models/domain/name_change_records.rb
  6. 51
      app/models/domain/name_change_subdomains.rb
  7. 31
      app/models/domain/tree_structure.rb
  8. 4
      config/initializers/devise.rb
  9. 26
      spec/models/domain_spec.rb

10
Gemfile

@ -7,9 +7,9 @@ gem 'rails', '3.2.6'
# gem 'pg'
gem 'mysql2'
gem 'devise', '~> 2.0.4'
gem 'devise', '~> 2.1.0'
gem 'cancan', '~> 1.6.7'
gem 'squeel', '~> 0.9.3'
gem 'squeel', '~> 1.0.0'
gem 'sentient_user', '~> 0.3.2'
gem 'userstamp_basic', '~> 0.1.0'
gem 'validates_hostname', '~> 1.0.0', git: 'https://github.com/KimNorgaard/validates_hostname.git'
@ -23,7 +23,7 @@ gem 'simple_form', '~> 2.0.0'
gem 'concerned_with', '~> 0.1.0'
gem 'navigasmic', '~> 0.5.6', git: 'https://github.com/jejacks0n/navigasmic.git'
gem 'rails-backbone', '~> 0.7.0'
gem 'acts_as_nested_interval', '~> 0.0.5'
gem 'acts_as_nested_interval', '~> 0.0.7'
# path: '/home/clyfe/dev/acts_as_nested_interval'
# git: 'https://github.com/clyfe/acts_as_nested_interval.git'
@ -41,8 +41,8 @@ end
gem 'jquery-rails'
gem 'dalli', '~> 1.1.3'
# gem 'foreigner' ?
gem 'active_scaffold', '~> 3.2.12'
# git: 'https://github.com/activescaffold/active_scaffold.git'
gem 'active_scaffold', '~> 3.2.12',
git: 'https://github.com/activescaffold/active_scaffold.git'
# path: '/home/clyfe/dev/active_scaffold'
gem 'pjax_rails', '~> 0.2.0'

52
Gemfile.lock

@ -4,6 +4,13 @@ GIT
specs:
validates_hostname (1.0.0)
GIT
remote: https://github.com/activescaffold/active_scaffold.git
revision: 0c01d763cfce3f910368491e672e2a7f493d916e
specs:
active_scaffold (3.2.12)
rails (>= 3.1.3)
GIT
remote: https://github.com/jejacks0n/navigasmic.git
revision: 1ffe437f279657c6fb87bb4b0215eb723df4ea7a
@ -29,8 +36,6 @@ GEM
active-model-email-validator (1.0.2)
activemodel
mail
active_scaffold (3.2.12)
rails (>= 3.1.3)
activemodel (3.2.6)
activesupport (= 3.2.6)
builder (~> 3.0.0)
@ -45,7 +50,7 @@ GEM
activesupport (3.2.6)
i18n (~> 0.6)
multi_json (~> 1.0)
acts_as_nested_interval (0.0.5)
acts_as_nested_interval (0.0.7)
rails (~> 3.2.1)
addressable (2.2.8)
arel (3.0.2)
@ -88,11 +93,11 @@ GEM
daemons (1.0.10)
dalli (1.1.5)
database_cleaner (0.7.2)
devise (2.0.4)
devise (2.1.2)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.0.3)
orm_adapter (~> 0.1)
railties (~> 3.1)
warden (~> 1.1.1)
warden (~> 1.2.1)
diff-lcs (1.1.3)
ejs (1.0.0)
erubis (2.7.0)
@ -126,11 +131,12 @@ GEM
railties (>= 3.2.0, < 5.0)
thor (~> 0.14)
json (1.7.3)
libnotify (0.7.3)
libnotify (0.7.4)
ffi (~> 1.0.11)
libv8 (3.3.10.4)
libwebsocket (0.1.3)
addressable
listen (0.4.5)
listen (0.4.6)
rb-fchange (~> 0.0.5)
rb-fsevent (~> 0.9.1)
rb-inotify (~> 0.8.8)
@ -156,12 +162,12 @@ GEM
activerecord (>= 3.0.0)
activesupport (>= 3.0.0)
nokogiri (1.5.4)
orm_adapter (0.0.7)
orm_adapter (0.1.0)
pjax_rails (0.2.1)
jquery-rails
polyamorous (0.5.0)
activerecord (~> 3.0)
polyglot (0.3.2)
polyglot (0.3.3)
rack (1.4.1)
rack-cache (1.2)
rack (>= 0.4)
@ -216,15 +222,14 @@ GEM
sexp_processor (~> 3.0)
ruby_parser (2.3.1)
sexp_processor (~> 3.0)
rubyzip (0.9.8)
rubyzip (0.9.9)
sass (3.1.19)
sass-rails (3.2.5)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
selenium-webdriver (2.22.2)
selenium-webdriver (2.24.0)
childprocess (>= 0.2.5)
ffi (~> 1.0)
libwebsocket (~> 0.1.3)
multi_json (~> 1.0)
rubyzip
@ -247,26 +252,25 @@ GEM
hike (~> 1.2)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
squeel (0.9.5)
squeel (1.0.6)
activerecord (~> 3.0)
activesupport (~> 3.0)
polyamorous (~> 0.5.0)
switch_user (0.6.0)
therubyracer (0.10.1)
libv8 (~> 3.3.10)
thor (0.15.2)
thor (0.15.3)
tilt (1.3.3)
tins (0.4.3)
treetop (1.4.10)
polyglot
treetop (1.4.9)
polyglot (>= 0.3.1)
tzinfo (0.3.33)
uglifier (1.2.4)
uglifier (1.2.5)
execjs (>= 0.3.0)
multi_json (>= 1.0.2)
multi_json (~> 1.3)
userstamp_basic (0.1.0)
sentient_user (>= 0.1.0)
warden (1.1.1)
warden (1.2.1)
rack (>= 1.0)
xpath (0.1.4)
nokogiri (~> 1.3)
@ -276,8 +280,8 @@ PLATFORMS
DEPENDENCIES
active-model-email-validator (~> 1.0.2)
active_scaffold (~> 3.2.12)
acts_as_nested_interval (~> 0.0.5)
active_scaffold (~> 3.2.12)!
acts_as_nested_interval (~> 0.0.7)
bootstrap-sass (~> 2.0.3)
cancan (~> 1.6.7)
capistrano (~> 2.9.0)
@ -288,7 +292,7 @@ DEPENDENCIES
concerned_with (~> 0.1.0)
dalli (~> 1.1.3)
database_cleaner (~> 0.7.1)
devise (~> 2.0.4)
devise (~> 2.1.0)
factory_girl_rails (~> 1.6.0)
faker (~> 1.0.1)
guard-rspec (~> 0.6.0)
@ -312,7 +316,7 @@ DEPENDENCIES
simplecov
sourcify (~> 0.6.0.rc1)
spork (~> 1.0.0.rc0)
squeel (~> 0.9.3)
squeel (~> 1.0.0)
switch_user (~> 0.6.0)
therubyracer
uglifier (>= 1.0.3)

8
app/controllers/domains_controller.rb

@ -1,13 +1,17 @@
class DomainsController < ApplicationController
active_scaffold :domain do |conf|
conf.columns = [:name, :ip, :records, :soa_record, :ns_records]
conf.columns = [:name, :ip, :records, :soa_record, :ns_records, :apply_subdomains]
conf.list.columns = [:name, :records, :permissions]
conf.create.columns = [:name, :ip, :soa_record, :ns_records]
conf.update.columns = [:name]
conf.update.columns = [:name, :apply_subdomains]
conf.columns[:name].description = 'Ex. "domain.com"'
conf.columns[:ip].description = 'Ex. "10.10.5.12", optional IP to associate your domain with'
conf.columns[:ns_records].show_blank_record = false
conf.columns[:permissions].label = 'Sharing'
conf.columns[:apply_subdomains].label = 'Also rename subdomains'
conf.columns[:apply_subdomains].description = 'If checked, will also rename all subdomains accordingly'
conf.columns[:apply_subdomains].form_ui = :checkbox
conf.columns[:apply_subdomains].options = { class: 'checkbox', checked: true }
conf.actions.exclude :show
conf.create.refresh_list = true # because tree structure might change
conf.update.refresh_list = true # because tree structure might change

2
app/models/domain.rb

@ -51,7 +51,7 @@ class Domain < ActiveRecord::Base
a_records.build(:content => ip) if ip.present?
end
concerned_with :name_change, :tree_structure
concerned_with :name_change_records, :name_change_subdomains, :tree_structure
scope :host_domains, where(:name => Settings.host_domains)

0
app/models/domain/name_change.rb → app/models/domain/name_change_records.rb

51
app/models/domain/name_change_subdomains.rb

@ -0,0 +1,51 @@
class Domain < ActiveRecord::Base
attr_accessor :apply_subdomains
def apply_subdomains=(v)
@apply_subdomains = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(v)
end
after_update do
if name_changed?
apply_subdomains ? chain_rename : sync_orphan_children
end
end
protected
# previous subdomains in the system for the previous domain name
# in case of domain name change
def previous_subdomains
Domain.where(:name_reversed.matches => "#{name_reversed_was}.%")
end
# only immediate children
def previous_children_subdomains
descendants = previous_subdomains.preorder.all
first = descendants.first
return [] unless first.present?
# only immediate children
depth = first.depth
descendants.select { |d| d.depth == depth }
end
# Syncs with nested interval when the parent is added later than the children
def sync_orphan_children
previous_children_subdomains.each do |subdomain|
subdomain.parent = nil
subdomain.save!
end
end
# applies the tail rename to children
def chain_rename
name_was_pattern = /#{Regexp.escape(name_was)}$/
previous_children_subdomains.each do |subdomain|
subdomain.name = subdomain.name.sub(name_was_pattern, name)
subdomain.apply_subdomains = true
subdomain.save! # rest will chain recursively
end
end
end

31
app/models/domain/tree_structure.rb

@ -7,6 +7,8 @@ class Domain < ActiveRecord::Base
sync_parent
end
after_save :sync_children
# this goes after sync_parent, to order callbacks correctly
acts_as_nested_interval virtual_root: true
@ -30,15 +32,14 @@ class Domain < ActiveRecord::Base
Ability::CRUD.all?{|operation| User.current.can?(operation, self)}
end
after_save :sync_children
# Returns the first immediate parent, if exists (and caches the search)
def parent_domain
return nil if name.nil?
@parent_domain ||= {}
@parent_domain[name] ||= _parent_domain
end
# subdomains in the system for the current domain name
def subdomains
Domain.where(:name_reversed.matches => "#{name_reversed}.%")
end
@ -47,6 +48,7 @@ class Domain < ActiveRecord::Base
name.end_with?('.' + domain.name)
end
# override
def self.rebuild_nested_interval_tree!
skip_callback :update, :before, :sync_children
super
@ -67,6 +69,17 @@ class Domain < ActiveRecord::Base
return nil
end
# only immediate children
def children_subdomains
descendants = subdomains.preorder.all
first = descendants.first
return [] unless first.present?
# only immediate children
depth = first.depth
descendants.select { |d| d.depth == depth }
end
# Syncs with nested interval when a child is added and parent exists
def sync_parent
if !@parent_synced && parent_domain.present? && self.parent_id != parent_domain.id
@ -76,18 +89,10 @@ class Domain < ActiveRecord::Base
# Syncs with nested interval when the parent is added later than the children
def sync_children
descendants = subdomains.preorder.all
first = descendants.first
return true unless first.present?
# only immediate children, rest will chain recursively
depth = first.depth
descendants = descendants.select { |d| d.depth == depth }
subdomains.each do |subdomain|
children_subdomains.each do |subdomain|
subdomain.parent = self
subdomain.parent_synced = true # no n+1
subdomain.save!
subdomain.save! # rest will chain recursively
end
end

4
config/initializers/devise.rb

@ -90,10 +90,6 @@ Devise.setup do |config|
# If true, extends the user's remember period when remembered via cookie.
# config.extend_remember_period = false
# If true, uses the password salt as remember token. This should be turned
# to false if you are not using database authenticatable.
config.use_salt_as_remember_token = true
# Options to be passed to the created cookie. For instance, you can set
# :secure => true in order to force SSL only cookies.
# config.cookie_options = {}

26
spec/models/domain_spec.rb

@ -113,4 +113,30 @@ describe Domain do
]
end
it "chains rename to children" do
domain
subdomain
subsubdomain
domain.apply_subdomains = true
domain.update_attributes(:name => "changed#{domain.name}")
subdomain.reload.name.should =~ /#{domain.name}$/
subsubdomain.reload.name.should =~ /#{domain.name}$/
end
it "orphans children" do
domain
subdomain
subsubdomain
domain.apply_subdomains = false
domain.update_attributes(:name => "changed#{domain.name}")
s = subdomain.reload
ss = subsubdomain.reload
s.name.should_not =~ /#{domain.name}$/
s.parent.should be_nil
ss.name.should_not =~ /#{domain.name}$/
ss.parent.should_not be_nil
end
end

Loading…
Cancel
Save