diff --git a/app/controllers/application.rb b/app/controllers/application.rb
index 537de40..7f8b1e6 100644
--- a/app/controllers/application.rb
+++ b/app/controllers/application.rb
@@ -1,4 +1,15 @@
# Filters added to this controller will be run for all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
-end
\ No newline at end of file
+
+ before_filter :detect_stuff_by_domain
+
+ protected
+
+ def detect_stuff_by_domain
+ @domain = Domain.find_by_name(request.host)
+ @virtual_community = @domain.virtual_community
+ @profile = @domain.profile
+ end
+
+end
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
new file mode 100644
index 0000000..fc0b474
--- /dev/null
+++ b/app/controllers/home_controller.rb
@@ -0,0 +1,2 @@
+class HomeController < ApplicationController
+end
diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb
new file mode 100644
index 0000000..23de56a
--- /dev/null
+++ b/app/helpers/home_helper.rb
@@ -0,0 +1,2 @@
+module HomeHelper
+end
diff --git a/app/models/domain.rb b/app/models/domain.rb
index efb979f..a39393b 100644
--- a/app/models/domain.rb
+++ b/app/models/domain.rb
@@ -1,7 +1,66 @@
class Domain < ActiveRecord::Base
+ # relationships
+ ###############
+
belongs_to :owner, :polymorphic => true
- validates_format_of :name, :with => /^(\w+\.)+\w+$/
+ # validations
+ #############
+
+ # name must be a sequence of word characters (a to z, plus 0 to 9,
+ # plus '_'). Letters must be lowercase
+ validates_format_of :name, :with => /^([a-z0-9_]+\.)+[a-z0-9_]+$/, :message => _('%{fn} must be composed only of lowercase latters (a to z), numbers (0 to 9) and "_"')
+
+ # checks validations that could not be expressed using Rails' predefined
+ # validations. In particular:
+ # * name must not start with 'www.'
+ def validate
+ if self.name =~ /^www\./
+ self.errors.add(:name, _('%{fn} must not start with www.'))
+ end
+ end
+
+ # we cannot have two domains with the same name
+ validates_uniqueness_of :name
+
+ # businessl logic
+ #################
+
+ # finds a domain by its name. The argument name can start with
+ # "www.", but it will be removed before searching. So searching for
+ # 'www.example.net' is exactly the same as searching for just 'example.net'
+ def self.find_by_name(name)
+ self.find(:first, :conditions => [ 'name = ?', self.extract_domain_name(name) ])
+ end
+
+ # turns the argument (expected to be a String) into a domain name that is
+ # accepted, by removing any leading 'www.' and turning the downcasing it.
+ def self.extract_domain_name(name)
+ name.downcase.sub(/^www\./, '')
+ end
+
+ # detects the VirtualCommunity to which this domain belongs, either if it's
+ # directly owned by one, or through a profile who owns the domain but belongs
+ # to a VirtualCommunity.
+ def virtual_community
+ case owner
+ when VirtualCommunity
+ owner
+ when Profile
+ owner.virtual_community
+ end
+ end
+
+ # returns the profile associated to this domain. Returns nil if the domain is
+ # not directly associated with a profile.
+ def profile
+ case owner
+ when VirtualCommunity
+ nil
+ when Profile
+ owner
+ end
+ end
end
diff --git a/app/models/profile.rb b/app/models/profile.rb
index df1798e..f34b2e5 100644
--- a/app/models/profile.rb
+++ b/app/models/profile.rb
@@ -1,4 +1,19 @@
+# A Profile is the representation and web-presence of an individual or an
+# organization. Every Profile is attached to its VirtualCommunity of origin,
+# which by default is the one returned by VirtualCommunity:default.
class Profile < ActiveRecord::Base
+
+ has_many :domains, :as => :owner
+ belongs_to :virtual_community
+
validates_presence_of :identifier
validates_format_of :identifier, :with => /^[a-z][a-z0-9_]+[a-z0-9]$/
+
+ # creates a new Profile. By default, it is attached to the default
+ # VirtualCommunity (see VirtualCommunity#default)
+ def initialize(*args)
+ super(*args)
+ self.virtual_community ||= VirtualCommunity.default
+ end
+
end
diff --git a/app/models/virtual_community.rb b/app/models/virtual_community.rb
index ef860fe..d6d4629 100644
--- a/app/models/virtual_community.rb
+++ b/app/models/virtual_community.rb
@@ -1,10 +1,27 @@
class VirtualCommunity < ActiveRecord::Base
+ # One VirtualCommunity can be reached by many domains
has_many :domains, :as => :owner
+ # name is mandatory
+ validates_presence_of :name
+
+ # only one virtual community can be the default one
+ validates_uniqueness_of :is_default, :if => (lambda do |virtual_community| virtual_community.is_default? end), :message => _('Only one Virtual Community can be the default one')
+
+ # VirtualCommunity configuration
serialize :configuration, Hash
+
+ # a Hash with configuration parameters for this community. The configuration
+ # contains general parameters of the VirtualCommunity as well as
+ # enabling/disabling optional features.
def configuration
self[:configuration] ||= Hash.new
end
+ # the default VirtualCommunity.
+ def self.default
+ self.find(:first, :conditions => [ 'is_default = ?', true ] )
+ end
+
end
diff --git a/app/views/home/index.rhtml b/app/views/home/index.rhtml
new file mode 100644
index 0000000..d1bf389
--- /dev/null
+++ b/app/views/home/index.rhtml
@@ -0,0 +1 @@
+Start page of Virtual Community <%# @virtual_community.name %>
diff --git a/config/routes.rb b/config/routes.rb
index 27fcae8..2757e85 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -11,7 +11,7 @@ ActionController::Routing::Routes.draw do |map|
# You can have the root of your site routed by hooking up ''
# -- just remember to delete public/index.html.
- # map.connect '', :controller => "welcome"
+ map.connect '', :controller => "home"
# Allow downloading Web Service WSDL as a file with an extension
# instead of a file named 'wsdl'
diff --git a/db/migrate/001_create_virtual_communities.rb b/db/migrate/001_create_virtual_communities.rb
index b306446..7411fd1 100644
--- a/db/migrate/001_create_virtual_communities.rb
+++ b/db/migrate/001_create_virtual_communities.rb
@@ -2,8 +2,8 @@ class CreateVirtualCommunities < ActiveRecord::Migration
def self.up
create_table :virtual_communities do |t|
t.column :name, :string
- t.column :domain, :string
t.column :configuration, :text
+ t.column :is_default, :boolean
end
end
diff --git a/db/migrate/002_create_profiles.rb b/db/migrate/002_create_profiles.rb
index f35ad93..865fbd8 100644
--- a/db/migrate/002_create_profiles.rb
+++ b/db/migrate/002_create_profiles.rb
@@ -3,6 +3,7 @@ class CreateProfiles < ActiveRecord::Migration
create_table :profiles do |t|
t.column :name, :string
t.column :identifier, :string
+ t.column :virtual_community_id, :integer
end
end
diff --git a/db/migrate/003_create_domains.rb b/db/migrate/003_create_domains.rb
index 1125251..233ccb1 100644
--- a/db/migrate/003_create_domains.rb
+++ b/db/migrate/003_create_domains.rb
@@ -2,7 +2,7 @@ class CreateDomains < ActiveRecord::Migration
def self.up
create_table :domains do |t|
t.column :name, :string
- t.column :ownwer_type, :string
+ t.column :owner_type, :string
t.column :owner_id, :integer
end
end
diff --git a/public/index.html b/public/index.html
deleted file mode 100644
index a2daab7..0000000
--- a/public/index.html
+++ /dev/null
@@ -1,277 +0,0 @@
-
-
-
-
- Ruby on Rails: Welcome aboard
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Getting started
-
Here’s how to get rolling:
-
-
- -
-
Create your databases and edit config/database.yml
- Rails needs to know your login and password.
-
-
- -
-
Use script/generate to create your models and controllers
- To see all available options, run it without parameters.
-
-
- -
-
Set up a default route and remove or rename this file
- Routes are setup in config/routes.rb.
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/fixtures/domains.yml b/test/fixtures/domains.yml
index b49c4eb..c8c7473 100644
--- a/test/fixtures/domains.yml
+++ b/test/fixtures/domains.yml
@@ -1,5 +1,21 @@
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
one:
id: 1
+ name: colivre.net
+ owner_type: VirtualCommunity
+ owner_id: 1
two:
id: 2
+ name: anhetegua.net
+ owner_type: VirtualCommunity
+ owner_id: 2
+three:
+ id: 3
+ name: johndoe.net
+ owner_type: Profile
+ owner_id: 1
+four:
+ id: 4
+ name: jrh.net
+ owner_type: Profile
+ owner_id: 2
diff --git a/test/fixtures/profiles.yml b/test/fixtures/profiles.yml
index 8794d28..1819f14 100644
--- a/test/fixtures/profiles.yml
+++ b/test/fixtures/profiles.yml
@@ -1,5 +1,11 @@
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
first:
id: 1
+ name: 'John Doe'
+ identifier: johndoe
+ virtual_community_id: 1
another:
id: 2
+ name: 'Joe Random Hacker'
+ identifier: joerandomhacker
+ virtual_community_id: 1
diff --git a/test/fixtures/virtual_communities.yml b/test/fixtures/virtual_communities.yml
index 7df90c7..57a90aa 100644
--- a/test/fixtures/virtual_communities.yml
+++ b/test/fixtures/virtual_communities.yml
@@ -1,9 +1,9 @@
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
first:
id: 1
- name: 'Anheteguá'
- domain: 'anhetegua.net'
+ name: 'Colivre.net'
+ is_default: true
another:
id: 2
- name: 'Colivre.net'
- domain: 'colivre.net'
+ name: 'Anheteguá'
+ is_default: false
diff --git a/test/functional/home_controller_test.rb b/test/functional/home_controller_test.rb
new file mode 100644
index 0000000..05018d0
--- /dev/null
+++ b/test/functional/home_controller_test.rb
@@ -0,0 +1,42 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'home_controller'
+
+# Re-raise errors caught by the controller.
+class HomeController; def rescue_action(e) raise e end; end
+
+class HomeControllerTest < Test::Unit::TestCase
+
+ fixtures :profiles, :virtual_communities, :domains
+
+ def setup
+ @controller = HomeController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ end
+
+ def test_detection_of_virtual_community_by_host
+ uses_host 'www.colivre.net'
+ get :index
+ assert_template 'index'
+
+ assert_kind_of VirtualCommunity, assigns(:virtual_community)
+
+ assert_kind_of Domain, assigns(:domain)
+ assert_equal 'colivre.net', assigns(:domain).name
+
+ assert_nil assigns(:profile)
+ end
+
+ def test_detect_profile_by_host
+ uses_host 'www.jrh.net'
+ get :index
+ assert_template 'index'
+
+ assert_kind_of VirtualCommunity, assigns(:virtual_community)
+
+ assert_kind_of Domain, assigns(:domain)
+ assert_equal 'jrh.net', assigns(:domain).name
+
+ assert_kind_of Profile, assigns(:profile)
+ end
+end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index a299c7f..f3d358e 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -25,4 +25,11 @@ class Test::Unit::TestCase
self.use_instantiated_fixtures = false
# Add more helper methods to be used by all tests here...
+
+ private
+
+ def uses_host(name)
+ @request.instance_variable_set('@host', name)
+ end
+
end
diff --git a/test/unit/domain_test.rb b/test/unit/domain_test.rb
index 171aa50..0ba50f6 100644
--- a/test/unit/domain_test.rb
+++ b/test/unit/domain_test.rb
@@ -1,21 +1,25 @@
require File.dirname(__FILE__) + '/../test_helper'
class DomainTest < Test::Unit::TestCase
- fixtures :domains
+ fixtures :domains, :virtual_communities, :profiles
# Replace this with your real tests.
def test_domain_name_format
c = Domain.new
- c.valid?
+ assert !c.valid?
assert c.errors.invalid?(:name)
c.name = 'bliblibli'
- c.valid?
+ assert !c.valid?
+ assert c.errors.invalid?(:name)
+
+ c.name = 'EXAMPLE.NET'
+ assert !c.valid?
assert c.errors.invalid?(:name)
c.name = 'test.net'
c.valid?
- assert ! c.errors.invalid?(:name)
+ assert !c.errors.invalid?(:name)
end
def test_owner
@@ -25,4 +29,58 @@ class DomainTest < Test::Unit::TestCase
assert_kind_of VirtualCommunity, d.owner
end
+ def test_get_domain_name
+ assert_equal 'example.net', Domain.extract_domain_name('www.example.net')
+ assert_equal 'example.net', Domain.extract_domain_name('WWW.EXAMPLE.NET')
+ end
+
+ def test_name_cannot_have_www
+ d = Domain.new
+ d.name = 'www.example.net'
+ d.valid?
+ assert d.errors.invalid?(:name)
+
+ d.name = 'example.net'
+ d.valid?
+ assert !d.errors.invalid?(:name)
+ end
+
+ def test_find_by_name
+ Domain.delete_all
+ Domain.create(:name => 'example.net')
+ d1 = Domain.find_by_name('example.net')
+ d2 = Domain.find_by_name('www.example.net')
+ assert !d1.nil?
+ assert !d2.nil?
+ assert d1 == d2
+ end
+
+ def test_unique_name
+ Domain.delete_all
+ assert Domain.create(:name => 'example.net')
+
+ d = Domain.new(:name => 'example.net')
+ assert !d.valid?
+ assert d.errors.invalid?(:name)
+ end
+
+ def test_virtual_community
+ # domain directly linked to VirtualCommunity
+ domain = Domain.find_by_name('colivre.net')
+ assert_kind_of VirtualCommunity, domain.owner
+ assert_kind_of VirtualCommunity, domain.virtual_community
+
+ # domain linked to Profile
+ domain = Domain.find_by_name('johndoe.net')
+ assert_kind_of Profile, domain.owner
+ assert_kind_of VirtualCommunity, domain.virtual_community
+ end
+
+ def test_profile
+ # domain linked to profile
+ assert_not_nil Domain.find_by_name('johndoe.net').profile
+ # domain linked to VirtualCommunity
+ assert_nil Domain.find_by_name('colivre.net').profile
+ end
+
end
diff --git a/test/unit/profile_test.rb b/test/unit/profile_test.rb
index 859d54d..54380d0 100644
--- a/test/unit/profile_test.rb
+++ b/test/unit/profile_test.rb
@@ -1,7 +1,7 @@
require File.dirname(__FILE__) + '/../test_helper'
class ProfileTest < Test::Unit::TestCase
- fixtures :profiles
+ fixtures :profiles, :virtual_communities
def test_identifier_validation
p = Profile.new
@@ -29,4 +29,14 @@ class ProfileTest < Test::Unit::TestCase
assert ! p.errors.invalid?(:identifier)
end
+ def test_has_domains
+ p = Profile.new
+ assert_kind_of Array, p.domains
+ end
+
+ def test_belongs_to_virtual_community_and_has_default
+ p = Profile.new
+ assert_kind_of VirtualCommunity, p.virtual_community
+ end
+
end
diff --git a/test/unit/virtual_community_test.rb b/test/unit/virtual_community_test.rb
index 8074bfb..5ffbd3d 100644
--- a/test/unit/virtual_community_test.rb
+++ b/test/unit/virtual_community_test.rb
@@ -4,8 +4,22 @@ class VirtualCommunityTest < Test::Unit::TestCase
fixtures :virtual_communities
def test_configuration
- c = VirtualCommunity.new
- assert_kind_of Hash, c.configuration
+ vc = VirtualCommunity.new
+ assert_kind_of Hash, vc.configuration
+ end
+
+ def test_exists_default_and_it_is_unique
+ VirtualCommunity.delete_all
+ vc = VirtualCommunity.new(:name => 'Test Community')
+ vc.is_default = true
+ assert vc.save
+
+ vc2 = VirtualCommunity.new(:name => 'Another Test Community')
+ vc2.is_default = true
+ assert !vc2.valid?
+ assert vc2.errors.invalid?(:is_default)
+
+ assert_equal vc, VirtualCommunity.default
end
end
--
libgit2 0.21.2