diff --git a/Gemfile.lock b/Gemfile.lock
index e0e4b68..075f929 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -94,7 +94,7 @@ GEM
i18n (~> 0.4)
ffi (1.0.9)
fssm (0.2.7)
- guard (0.8.5)
+ guard (0.8.6)
thor (~> 0.14.6)
guard-rspec (0.4.5)
guard (>= 0.4.0)
@@ -133,7 +133,7 @@ GEM
pjax_rails (0.1.10)
jquery-rails
polyglot (0.3.2)
- rack (1.3.4)
+ rack (1.3.5)
rack-cache (1.1)
rack (>= 0.4)
rack-mount (0.8.3)
@@ -161,7 +161,7 @@ GEM
thor (~> 0.14.6)
rake (0.9.2)
rb-fsevent (0.4.3.1)
- rdoc (3.10)
+ rdoc (3.11)
json (~> 1.4)
rspec (2.6.0)
rspec-core (~> 2.6.0)
@@ -194,7 +194,7 @@ GEM
sprockets (2.0.3)
hike (~> 1.2)
rack (~> 1.0)
- tilt (~> 1.1, != 1.3.0)
+ tilt (!= 1.3.0, ~> 1.1)
therubyracer (0.9.8)
libv8 (~> 3.3.10)
thor (0.14.6)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index cbf56fd..a574705 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -29,4 +29,8 @@ class ApplicationController < ActionController::Base
end
helper_method :client_remote_ip
+ def current_ability
+ @current_ability ||= ::Ability.new(:user => current_user)
+ end
+
end
diff --git a/app/controllers/hosts_controller.rb b/app/controllers/hosts_controller.rb
new file mode 100644
index 0000000..376314c
--- /dev/null
+++ b/app/controllers/hosts_controller.rb
@@ -0,0 +1,32 @@
+class HostsController < ApplicationController
+ active_scaffold :a do |conf|
+ conf.columns = [:name, :host_domain, :content, :ttl, :change_date, :authentication_token]
+ conf.list.columns = [:name, :content, :ttl, :change_date, :authentication_token]
+ conf.create.columns = [:name, :host_domain, :content, :ttl,]
+ conf.update.columns = [:name, :host_domain, :content, :ttl]
+ conf.list.label = 'Hosts'
+ conf.create.link.label = "Add Host"
+ conf.columns[:host_domain].form_ui = :select
+ conf.columns[:host_domain].options = {:options => Settings.host_domains}
+ conf.columns[:name].label = 'Host'
+ conf.columns[:content].label = 'IP'
+ conf.columns[:content].description = 'Ex. "10.10.5.12"'
+ conf.columns[:change_date].list_ui = :timestamp
+ conf.columns[:ttl].options = {:i18n_number => {:delimiter => ''}}
+ conf.actions.exclude :show
+ end
+
+ protected
+
+ def new_model
+ record = super
+ record.content = client_remote_ip
+ before_create_save(record)
+ record
+ end
+
+ def before_create_save(record)
+ record.user = current_user
+ end
+
+end
diff --git a/app/helpers/hosts_helper.rb b/app/helpers/hosts_helper.rb
new file mode 100644
index 0000000..3349e1d
--- /dev/null
+++ b/app/helpers/hosts_helper.rb
@@ -0,0 +1,2 @@
+module HostsHelper
+end
\ No newline at end of file
diff --git a/app/models/a.rb b/app/models/a.rb
index 323aaf4..39be01f 100644
--- a/app/models/a.rb
+++ b/app/models/a.rb
@@ -14,4 +14,13 @@ class A < Record
validates :name, :hostname => {:allow_underscore => true, :allow_wildcard_hostname => true}
validates :content, :presence => true, :ip => {:ip_type => :v4} # Only accept valid IPv4 addresses
+ attr_accessor :host_domain
+ validates :host_domain, :inclusion => {:in => Settings.host_domains}
+
+ before_validation do
+ if host_domain.present? && Settings.host_domains.include?(host_domain)
+ self.domain_id = Domain.find_by_name(host_domain).try(:id)
+ end
+ end
+
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 31d39c2..1d15d8a 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -1,27 +1,24 @@
class Ability
include CanCan::Ability
+ attr_accessor :user
+ attr_accessor :context
- def initialize(user)
-
- user ||= User.new
+ def initialize(options)
+ @user = options[:user] || User.new
+ @context = options[:context] || :application
+
if user.persisted?
+
+ # can manage his domains and records
can :manage, Domain, :user_id => user.id
can :manage, Record, :domain => {:user_id => user.id}
cannot :delete, SOA # it's deleted with the parent domain
+
+ # can manage his hosts
+ can :manage, A, :user_id => user.id #, :domain => {:name => Settings.host_domains}
+
end
- # The first argument to `can` is the action you are giving the user permission to do.
- # If you pass :manage it will apply to every action. Other common actions here are
- # :read, :create, :update and :destroy.
- #
- # The second argument is the resource the user can perform the action on. If you pass
- # :all it will apply to every resource. Otherwise pass a Ruby class of the resource.
- #
- # The third argument is an optional hash of conditions to further filter the objects.
- # For example, here the user can only update published articles.
- #
- # can :update, Article, :published => true
- #
# See the wiki for details: https://github.com/ryanb/cancan/wiki/Defining-Abilities
end
end
diff --git a/app/models/domain.rb b/app/models/domain.rb
index a1c8089..7d391e6 100644
--- a/app/models/domain.rb
+++ b/app/models/domain.rb
@@ -5,8 +5,8 @@ class Domain < ActiveRecord::Base
# optional IP for create form, results in a type A record
attr_accessor :ip
- belongs_to :user
- has_many :records, :dependent => :destroy, :inverse_of => :domain
+ belongs_to :user, :inverse_of => :domain
+ has_many :records, :inverse_of => :domain, :dependent => :destroy
cattr_reader :types
@@types = ['NATIVE', 'MASTER', 'SLAVE', 'SUPERSLAVE']
@@ -85,6 +85,7 @@ class Domain < ActiveRecord::Base
end
end
+ scope :host_domains, where(:name => Settings.host_domains)
def setup(email)
build_soa_record
diff --git a/app/models/record.rb b/app/models/record.rb
index f21e053..ebe202e 100644
--- a/app/models/record.rb
+++ b/app/models/record.rb
@@ -1,5 +1,6 @@
class Record < ActiveRecord::Base
belongs_to :domain, :inverse_of => :records
+ belongs_to :user, :inverse_of => :records
cattr_reader :types
@@types = %w(SOA NS A MX TXT CNAME)
diff --git a/app/views/fragments/_top.html.erb b/app/views/fragments/_top.html.erb
index 2b5532a..c7fabdd 100644
--- a/app/views/fragments/_top.html.erb
+++ b/app/views/fragments/_top.html.erb
@@ -6,18 +6,23 @@
<% if user_signed_in? %>
<%#= link_to('Dashboard', dashboard_path, :data => {:pjax => '#main'}) %>
<%= link_to 'Manage Domains', domains_path, :data => {:pjax => '#main'} %>
+ <%= link_to 'Manage Hosts', hosts_path, :data => {:pjax => '#main'} %>
<% else %>
<%= link_to('Home', root_path, :data => {:pjax => '#main'}) %>
+ <%= link_to('About', page_path('about'), :data => {:pjax => '#main'}) %>
+ <%= link_to('Team', page_path('team'), :data => {:pjax => '#main'}) %>
+ <%= link_to('Contact', page_path('contact'), :data => {:pjax => '#main'}) %>
+ <%= link_to('Help & Support', page_path('help'), :data => {:pjax => '#main'}) %>
<% end %>
- <%= link_to('About', page_path('about'), :data => {:pjax => '#main'}) %>
- <%= link_to('Team', page_path('team'), :data => {:pjax => '#main'}) %>
- <%= link_to('Contact', page_path('contact'), :data => {:pjax => '#main'}) %>
- <%= link_to('Help & Support', page_path('help'), :data => {:pjax => '#main'}) %>
<% if user_signed_in? %>
+ - <%= link_to('About', page_path('about'), :data => {:pjax => '#main'}) %>
+ - <%= link_to('Team', page_path('team'), :data => {:pjax => '#main'}) %>
+ - <%= link_to('Contact', page_path('contact'), :data => {:pjax => '#main'}) %>
+ - <%= link_to('Help & Support', page_path('help'), :data => {:pjax => '#main'}) %>
- <%= link_to(current_user.email, edit_user_registration_path, :title => "IP: #{client_remote_ip}", :data => {:pjax => '#main'}) %>
- <%= link_to('Sign out', destroy_user_session_path, :method => :delete) %>
<% else %>
diff --git a/config/routes.rb b/config/routes.rb
index 2998489..0d280f4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -6,6 +6,10 @@ Entrydns::Application.routes.draw do
as_routes
end
+ resources :hosts do
+ as_routes
+ end
+
put '/records/modify/:authentication_token', :to => 'records#modify', :as => :modify_record
resources :records do
as_routes
diff --git a/config/settings.sample.yml b/config/settings.sample.yml
index 4c73a10..adc03ec 100644
--- a/config/settings.sample.yml
+++ b/config/settings.sample.yml
@@ -6,3 +6,5 @@ ns:
# - ns3.entrydns.net
# - ns4.entrydns.net
default_prio: 10
+host_domains:
+ - entrydns.net
diff --git a/db/migrate/20111018100348_add_user_id_to_records.rb b/db/migrate/20111018100348_add_user_id_to_records.rb
new file mode 100644
index 0000000..78474fc
--- /dev/null
+++ b/db/migrate/20111018100348_add_user_id_to_records.rb
@@ -0,0 +1,5 @@
+class AddUserIdToRecords < ActiveRecord::Migration
+ def change
+ add_column :records, :user_id, :integer
+ end
+end
diff --git a/db/seeds.rb b/db/seeds.rb
index bbe05e6..a272a4b 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -1,3 +1,19 @@
+
+# an user for administrative purposes
+admin = User.create(
+ :email => 'admin@entrydns.com',
+ :password => 'garlik1',
+ :password_confirmation => 'garlik1'
+)
+admin.confirm!
+
+for name in Settings.host_domains
+ entrudns_org = Domain.new(:name => name, :type => 'NATIVE', :user_id => admin.id)
+ entrudns_org.setup(admin.email)
+ entrudns_org.save!
+end
+
+# sample user
user = User.create(
:email => 'user@app.com',
:password => 'useruser',
diff --git a/spec/controllers/hosts_controller_spec.rb b/spec/controllers/hosts_controller_spec.rb
new file mode 100644
index 0000000..8d9b9a9
--- /dev/null
+++ b/spec/controllers/hosts_controller_spec.rb
@@ -0,0 +1,157 @@
+require 'spec_helper'
+
+# This spec was generated by rspec-rails when you ran the scaffold generator.
+# It demonstrates how one might use RSpec to specify the controller code that
+# was generated by Rails when you ran the scaffold generator.
+#
+# It assumes that the implementation code is generated by the rails scaffold
+# generator. If you are using any extension libraries to generate different
+# controller code, this generated spec may or may not pass.
+#
+# It only uses APIs available in rails and/or rspec-rails. There are a number
+# of tools you can use to make these specs even more expressive, but we're
+# sticking to rails and rspec-rails APIs to keep things simple and stable.
+#
+# Compared to earlier versions of this generator, there is very limited use of
+# stubs and message expectations in this spec. Stubs are only used when there
+# is no simpler way to get a handle on the object needed for the example.
+# Message expectations are only used when there is no simpler way to specify
+# that an instance is receiving a specific message.
+
+describe HostsController do
+
+ # This should return the minimal set of attributes required to create a valid
+ # Host. As you add validations to Host, be sure to
+ # update the return value of this method accordingly.
+ def valid_attributes
+ {}
+ end
+
+ describe "GET index" do
+ it "assigns all hosts as @hosts" do
+ host = Host.create! valid_attributes
+ get :index
+ assigns(:hosts).should eq([host])
+ end
+ end
+
+ describe "GET show" do
+ it "assigns the requested host as @host" do
+ host = Host.create! valid_attributes
+ get :show, :id => host.id.to_s
+ assigns(:host).should eq(host)
+ end
+ end
+
+ describe "GET new" do
+ it "assigns a new host as @host" do
+ get :new
+ assigns(:host).should be_a_new(Host)
+ end
+ end
+
+ describe "GET edit" do
+ it "assigns the requested host as @host" do
+ host = Host.create! valid_attributes
+ get :edit, :id => host.id.to_s
+ assigns(:host).should eq(host)
+ end
+ end
+
+ describe "POST create" do
+ describe "with valid params" do
+ it "creates a new Host" do
+ expect {
+ post :create, :host => valid_attributes
+ }.to change(Host, :count).by(1)
+ end
+
+ it "assigns a newly created host as @host" do
+ post :create, :host => valid_attributes
+ assigns(:host).should be_a(Host)
+ assigns(:host).should be_persisted
+ end
+
+ it "redirects to the created host" do
+ post :create, :host => valid_attributes
+ response.should redirect_to(Host.last)
+ end
+ end
+
+ describe "with invalid params" do
+ it "assigns a newly created but unsaved host as @host" do
+ # Trigger the behavior that occurs when invalid params are submitted
+ Host.any_instance.stub(:save).and_return(false)
+ post :create, :host => {}
+ assigns(:host).should be_a_new(Host)
+ end
+
+ it "re-renders the 'new' template" do
+ # Trigger the behavior that occurs when invalid params are submitted
+ Host.any_instance.stub(:save).and_return(false)
+ post :create, :host => {}
+ response.should render_template("new")
+ end
+ end
+ end
+
+ describe "PUT update" do
+ describe "with valid params" do
+ it "updates the requested host" do
+ host = Host.create! valid_attributes
+ # Assuming there are no other hosts in the database, this
+ # specifies that the Host created on the previous line
+ # receives the :update_attributes message with whatever params are
+ # submitted in the request.
+ Host.any_instance.should_receive(:update_attributes).with({'these' => 'params'})
+ put :update, :id => host.id, :host => {'these' => 'params'}
+ end
+
+ it "assigns the requested host as @host" do
+ host = Host.create! valid_attributes
+ put :update, :id => host.id, :host => valid_attributes
+ assigns(:host).should eq(host)
+ end
+
+ it "redirects to the host" do
+ host = Host.create! valid_attributes
+ put :update, :id => host.id, :host => valid_attributes
+ response.should redirect_to(host)
+ end
+ end
+
+ describe "with invalid params" do
+ it "assigns the host as @host" do
+ host = Host.create! valid_attributes
+ # Trigger the behavior that occurs when invalid params are submitted
+ Host.any_instance.stub(:save).and_return(false)
+ put :update, :id => host.id.to_s, :host => {}
+ assigns(:host).should eq(host)
+ end
+
+ it "re-renders the 'edit' template" do
+ host = Host.create! valid_attributes
+ # Trigger the behavior that occurs when invalid params are submitted
+ Host.any_instance.stub(:save).and_return(false)
+ put :update, :id => host.id.to_s, :host => {}
+ response.should render_template("edit")
+ end
+ end
+ end
+
+ describe "DELETE destroy" do
+ it "destroys the requested host" do
+ host = Host.create! valid_attributes
+ expect {
+ delete :destroy, :id => host.id.to_s
+ }.to change(Host, :count).by(-1)
+ end
+
+ it "redirects to the hosts list" do
+ host = Host.create! valid_attributes
+ delete :destroy, :id => host.id.to_s
+ response.should redirect_to(hosts_url)
+ end
+ end
+
+end
diff --git a/spec/helpers/hosts_helper_spec.rb b/spec/helpers/hosts_helper_spec.rb
new file mode 100644
index 0000000..29cad03
--- /dev/null
+++ b/spec/helpers/hosts_helper_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+# Specs in this file have access to a helper object that includes
+# the HostsHelper. For example:
+#
+# describe HostsHelper do
+# describe "string concat" do
+# it "concats two strings with spaces" do
+# helper.concat_strings("this","that").should == "this that"
+# end
+# end
+# end
+describe HostsHelper do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/requests/hosts_spec.rb b/spec/requests/hosts_spec.rb
new file mode 100644
index 0000000..3bd06ee
--- /dev/null
+++ b/spec/requests/hosts_spec.rb
@@ -0,0 +1,11 @@
+require 'spec_helper'
+
+describe "Hosts" do
+ describe "GET /hosts" do
+ it "works! (now write some real specs)" do
+ # Run the generator again with the --webrat flag if you want to use webrat methods/matchers
+ get hosts_path
+ response.status.should be(200)
+ end
+ end
+end
diff --git a/spec/routing/hosts_routing_spec.rb b/spec/routing/hosts_routing_spec.rb
new file mode 100644
index 0000000..2f94d0e
--- /dev/null
+++ b/spec/routing/hosts_routing_spec.rb
@@ -0,0 +1,35 @@
+require "spec_helper"
+
+describe HostsController do
+ describe "routing" do
+
+ it "routes to #index" do
+ get("/hosts").should route_to("hosts#index")
+ end
+
+ it "routes to #new" do
+ get("/hosts/new").should route_to("hosts#new")
+ end
+
+ it "routes to #show" do
+ get("/hosts/1").should route_to("hosts#show", :id => "1")
+ end
+
+ it "routes to #edit" do
+ get("/hosts/1/edit").should route_to("hosts#edit", :id => "1")
+ end
+
+ it "routes to #create" do
+ post("/hosts").should route_to("hosts#create")
+ end
+
+ it "routes to #update" do
+ put("/hosts/1").should route_to("hosts#update", :id => "1")
+ end
+
+ it "routes to #destroy" do
+ delete("/hosts/1").should route_to("hosts#destroy", :id => "1")
+ end
+
+ end
+end
diff --git a/spec/views/hosts/edit.html.erb_spec.rb b/spec/views/hosts/edit.html.erb_spec.rb
new file mode 100644
index 0000000..756d3c3
--- /dev/null
+++ b/spec/views/hosts/edit.html.erb_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+describe "hosts/edit.html.erb" do
+ before(:each) do
+ @host = assign(:host, stub_model(Host))
+ end
+
+ it "renders the edit host form" do
+ render
+
+ # Run the generator again with the --webrat flag if you want to use webrat matchers
+ assert_select "form", :action => hosts_path(@host), :method => "post" do
+ end
+ end
+end
diff --git a/spec/views/hosts/index.html.erb_spec.rb b/spec/views/hosts/index.html.erb_spec.rb
new file mode 100644
index 0000000..bbc0fb6
--- /dev/null
+++ b/spec/views/hosts/index.html.erb_spec.rb
@@ -0,0 +1,14 @@
+require 'spec_helper'
+
+describe "hosts/index.html.erb" do
+ before(:each) do
+ assign(:hosts, [
+ stub_model(Host),
+ stub_model(Host)
+ ])
+ end
+
+ it "renders a list of hosts" do
+ render
+ end
+end
diff --git a/spec/views/hosts/new.html.erb_spec.rb b/spec/views/hosts/new.html.erb_spec.rb
new file mode 100644
index 0000000..5ed15ef
--- /dev/null
+++ b/spec/views/hosts/new.html.erb_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+describe "hosts/new.html.erb" do
+ before(:each) do
+ assign(:host, stub_model(Host).as_new_record)
+ end
+
+ it "renders new host form" do
+ render
+
+ # Run the generator again with the --webrat flag if you want to use webrat matchers
+ assert_select "form", :action => hosts_path, :method => "post" do
+ end
+ end
+end
diff --git a/spec/views/hosts/show.html.erb_spec.rb b/spec/views/hosts/show.html.erb_spec.rb
new file mode 100644
index 0000000..b6c499c
--- /dev/null
+++ b/spec/views/hosts/show.html.erb_spec.rb
@@ -0,0 +1,11 @@
+require 'spec_helper'
+
+describe "hosts/show.html.erb" do
+ before(:each) do
+ @host = assign(:host, stub_model(Host))
+ end
+
+ it "renders attributes in " do
+ render
+ end
+end