From 09a87726fac518a161779a7348882cd28a89d689 Mon Sep 17 00:00:00 2001 From: AntonioTerceiro Date: Thu, 5 Jul 2007 21:32:37 +0000 Subject: [PATCH] ActionItem8: initial effort on VirtualCommunity, Profile and Domain --- app/controllers/application.rb | 13 ++++++++++++- app/controllers/home_controller.rb | 2 ++ app/helpers/home_helper.rb | 2 ++ app/models/domain.rb | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- app/models/profile.rb | 15 +++++++++++++++ app/models/virtual_community.rb | 17 +++++++++++++++++ app/views/home/index.rhtml | 1 + config/routes.rb | 2 +- db/migrate/001_create_virtual_communities.rb | 2 +- db/migrate/002_create_profiles.rb | 1 + db/migrate/003_create_domains.rb | 2 +- public/index.html | 277 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- test/fixtures/domains.yml | 16 ++++++++++++++++ test/fixtures/profiles.yml | 6 ++++++ test/fixtures/virtual_communities.yml | 8 ++++---- test/functional/home_controller_test.rb | 42 ++++++++++++++++++++++++++++++++++++++++++ test/test_helper.rb | 7 +++++++ test/unit/domain_test.rb | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- test/unit/profile_test.rb | 12 +++++++++++- test/unit/virtual_community_test.rb | 18 ++++++++++++++++-- 20 files changed, 277 insertions(+), 293 deletions(-) create mode 100644 app/controllers/home_controller.rb create mode 100644 app/helpers/home_helper.rb create mode 100644 app/views/home/index.rhtml delete mode 100644 public/index.html create mode 100644 test/functional/home_controller_test.rb 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:

- -
    -
  1. -

    Create your databases and edit config/database.yml

    -

    Rails needs to know your login and password.

    -
  2. - -
  3. -

    Use script/generate to create your models and controllers

    -

    To see all available options, run it without parameters.

    -
  4. - -
  5. -

    Set up a default route and remove or rename this file

    -

    Routes are setup in config/routes.rb.

    -
  6. -
-
-
- - -
- - \ 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