From 30789cbbc37a3f94b4b266dfc99d95ed847f6baa Mon Sep 17 00:00:00 2001 From: dinedine Date: Tue, 13 Apr 2010 15:24:12 +0200 Subject: [PATCH] adding devise + create account model and bind it to site --- app/models/account.rb | 32 +++++++++------ app/models/site.rb | 9 +++++ app/views/devise/confirmations/new.html.erb | 12 ++++++ .../mailer/confirmation_instructions.html.erb | 5 +++ .../reset_password_instructions.html.erb | 8 ++++ .../mailer/unlock_instructions.html.erb | 7 ++++ app/views/devise/passwords/edit.html.erb | 16 ++++++++ app/views/devise/passwords/new.html.erb | 12 ++++++ app/views/devise/registrations/edit.html.erb | 25 ++++++++++++ app/views/devise/registrations/new.html.erb | 17 ++++++++ app/views/devise/sessions/new.html.erb | 17 ++++++++ app/views/devise/shared/_links.erb | 19 +++++++++ app/views/devise/unlocks/new.html.erb | 12 ++++++ config/initializers/devise.rb | 1 - config/initializers/locomotive.rb | 5 ++- config/routes.rb | 1 + db/seeds.rb | 3 +- spec/factories.rb | 17 ++++---- spec/models/account_spec.rb | 40 +++++++++++++++++++ spec/models/site_spec.rb | 11 +++++ 20 files changed, 244 insertions(+), 25 deletions(-) create mode 100644 app/views/devise/confirmations/new.html.erb create mode 100644 app/views/devise/mailer/confirmation_instructions.html.erb create mode 100644 app/views/devise/mailer/reset_password_instructions.html.erb create mode 100644 app/views/devise/mailer/unlock_instructions.html.erb create mode 100644 app/views/devise/passwords/edit.html.erb create mode 100644 app/views/devise/passwords/new.html.erb create mode 100644 app/views/devise/registrations/edit.html.erb create mode 100644 app/views/devise/registrations/new.html.erb create mode 100644 app/views/devise/sessions/new.html.erb create mode 100644 app/views/devise/shared/_links.erb create mode 100644 app/views/devise/unlocks/new.html.erb create mode 100644 spec/models/account_spec.rb diff --git a/app/models/account.rb b/app/models/account.rb index 515ed2e7..a9976463 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -1,17 +1,23 @@ class Account + include Mongoid::Document + include Mongoid::Timestamps - # include MongoMapper::Document - - ## Attributes - # key :name - # key :locale - # timestamps! - - # Include default devise modules. Others available are: - # :http_authenticatable, :token_authenticatable, :lockable, :timeoutable and :activatable - # devise :registerable, :authenticatable, :confirmable, :recoverable, - # :rememberable, :trackable, :validatable + # devise modules + devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable - # Setup accessible (or protected) attributes for your model - # attr_accessible :email, :password, :password_confirmation + # attr_accessible :email, :password, :password_confirmation # TODO + + ## attributes ## + field :name + field :locale, :default => 'en' + + ## validations ## + validates_presence_of :name + + ## associations ## + + def sites + Site.where({ :account_ids => self._id }) + end + end diff --git a/app/models/site.rb b/app/models/site.rb index a9361723..0419113d 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -6,6 +6,7 @@ class Site field :name field :subdomain, :type => String field :domains, :type => Array, :default => [] + field :account_ids, :type => Array, :default => [] ## validations ## validates_presence_of :name, :subdomain @@ -25,6 +26,14 @@ class Site add_dirty_methods :domains ## methods ## + + def accounts + Account.criteria.in(:_id => self.account_ids) + end + + def accounts=(models_or_ids) + self.account_ids = [*models_or_ids].collect { |object| object.respond_to?(:to_i) ? object : object.id }.uniq + end def add_subdomain_to_domains self.domains ||= [] diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb new file mode 100644 index 00000000..8ce5cc0f --- /dev/null +++ b/app/views/devise/confirmations/new.html.erb @@ -0,0 +1,12 @@ +

Resend confirmation instructions

+ +<%= form_for(resource_name, resource, :url => confirmation_path(resource_name)) do |f| %> + <%= f.error_messages %> + +

<%= f.label :email %>

+

<%= f.text_field :email %>

+ +

<%= f.submit "Resend confirmation instructions" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> \ No newline at end of file diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb new file mode 100644 index 00000000..a6ea8ca1 --- /dev/null +++ b/app/views/devise/mailer/confirmation_instructions.html.erb @@ -0,0 +1,5 @@ +

Welcome <%= @resource.email %>!

+ +

You can confirm your account through the link below:

+ +

<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>

diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb new file mode 100644 index 00000000..ae9e888a --- /dev/null +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +

Hello <%= @resource.email %>!

+ +

Someone has requested a link to change your password, and you can do this through the link below.

+ +

<%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %>

+ +

If you didn't request this, please ignore this email.

+

Your password won't change until you access the link above and create a new one.

diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb new file mode 100644 index 00000000..2263c219 --- /dev/null +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @resource.email %>!

+ +

Your account has been locked due to an excessive amount of unsuccessful sign in attempts.

+ +

Click the link below to unlock your account:

+ +

<%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token) %>

diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb new file mode 100644 index 00000000..82858b4c --- /dev/null +++ b/app/views/devise/passwords/edit.html.erb @@ -0,0 +1,16 @@ +

Change your password

+ +<%= form_for(resource_name, resource, :url => password_path(resource_name), :html => { :method => :put }) do |f| %> + <%= f.error_messages %> + <%= f.hidden_field :reset_password_token %> + +

<%= f.label :password %>

+

<%= f.password_field :password %>

+ +

<%= f.label :password_confirmation %>

+

<%= f.password_field :password_confirmation %>

+ +

<%= f.submit "Change my password" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> \ No newline at end of file diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb new file mode 100644 index 00000000..f055608a --- /dev/null +++ b/app/views/devise/passwords/new.html.erb @@ -0,0 +1,12 @@ +

Forgot your password?

+ +<%= form_for(resource_name, resource, :url => password_path(resource_name)) do |f| %> + <%= f.error_messages %> + +

<%= f.label :email %>

+

<%= f.text_field :email %>

+ +

<%= f.submit "Send me reset password instructions" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> \ No newline at end of file diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb new file mode 100644 index 00000000..6de7b26a --- /dev/null +++ b/app/views/devise/registrations/edit.html.erb @@ -0,0 +1,25 @@ +

Edit <%= resource_name.to_s.humanize %>

+ +<%= form_for(resource_name, resource, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %> + <%= f.error_messages %> + +

<%= f.label :email %>

+

<%= f.text_field :email %>

+ +

<%= f.label :password %> (leave blank if you don't want to change it)

+

<%= f.password_field :password %>

+ +

<%= f.label :password_confirmation %>

+

<%= f.password_field :password_confirmation %>

+ +

<%= f.label :current_password %> (we need your current password to confirm your changes)

+

<%= f.password_field :current_password %>

+ +

<%= f.submit "Update" %>

+<% end %> + +

Cancel my account

+ +

Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.

+ +<%= link_to "Back", :back %> diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb new file mode 100644 index 00000000..3c2b1a8b --- /dev/null +++ b/app/views/devise/registrations/new.html.erb @@ -0,0 +1,17 @@ +

Sign up

+ +<%= form_for(resource_name, resource, :url => registration_path(resource_name)) do |f| %> + <%= f.error_messages %> +

<%= f.label :email %>

+

<%= f.text_field :email %>

+ +

<%= f.label :password %>

+

<%= f.password_field :password %>

+ +

<%= f.label :password_confirmation %>

+

<%= f.password_field :password_confirmation %>

+ +

<%= f.submit "Sign up" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb new file mode 100644 index 00000000..3762d08e --- /dev/null +++ b/app/views/devise/sessions/new.html.erb @@ -0,0 +1,17 @@ +

Sign in

+ +<%= form_for(resource_name, resource, :url => session_path(resource_name)) do |f| %> +

<%= f.label :email %>

+

<%= f.text_field :email %>

+ +

<%= f.label :password %>

+

<%= f.password_field :password %>

+ + <% if devise_mapping.rememberable? -%> +

<%= f.check_box :remember_me %> <%= f.label :remember_me %>

+ <% end -%> + +

<%= f.submit "Sign in" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> \ No newline at end of file diff --git a/app/views/devise/shared/_links.erb b/app/views/devise/shared/_links.erb new file mode 100644 index 00000000..56b9cc73 --- /dev/null +++ b/app/views/devise/shared/_links.erb @@ -0,0 +1,19 @@ +<%- if controller_name != 'sessions' %> + <%= link_to "Sign in", new_session_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.registerable? && controller_name != 'registrations' %> + <%= link_to "Sign up", new_registration_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.recoverable? && controller_name != 'passwords' %> + <%= link_to "Forgot your password?", new_password_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> + <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
+<% end -%> + +<%- if devise_mapping.lockable? && controller_name != 'unlocks' %> + <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
+<% end -%> diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb new file mode 100644 index 00000000..401bfa8c --- /dev/null +++ b/app/views/devise/unlocks/new.html.erb @@ -0,0 +1,12 @@ +

Resend unlock instructions

+ +<%= form_for(resource_name, resource, :url => unlock_path(resource_name)) do |f| %> + <%= f.error_messages %> + +

<%= f.label :email %>

+

<%= f.text_field :email %>

+ +

<%= f.submit "Resend unlock instructions" %>

+<% end %> + +<%= render :partial => "devise/shared/links" %> \ No newline at end of file diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 35f45744..f316c5b0 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -84,7 +84,6 @@ Devise.setup do |config| # ==> General configuration # Load and configure the ORM. Supports :active_record (default), :mongoid # (requires mongo_ext installed) and :data_mapper (experimental). - # require 'devise/orm/active_record' require 'devise/orm/mongoid' # Turn scoped views on. Before rendering "sessions/new", it will first check for diff --git a/config/initializers/locomotive.rb b/config/initializers/locomotive.rb index b02ad88d..c7765e7e 100644 --- a/config/initializers/locomotive.rb +++ b/config/initializers/locomotive.rb @@ -2,4 +2,7 @@ require 'lib/locomotive.rb' Locomotive.configure do |config| config.default_domain = 'example.com' -end \ No newline at end of file +end + +# TODO: embed it in Locomotive +ActionMailer::Base.default_url_options[:host] = Locomotive.config.default_domain + (Rails.env.development? ? ':3000' : '') \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 34cb5584..1b4f85ed 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,6 +2,7 @@ Locomotive::Application.routes.draw do |map| constraints(Locomotive::Routing::DefaultConstraint) do root :to => 'home#show' + devise_for :accounts end match '/' => 'pages#show' diff --git a/db/seeds.rb b/db/seeds.rb index 3c45d823..eaf4226d 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -7,4 +7,5 @@ # Mayor.create(:name => 'Daley', :city => cities.first) -Site.create! :name => 'Locomotive test website', :subdomain => 'test' \ No newline at end of file +Site.create! :name => 'Locomotive test website', :subdomain => 'test' +Account.create :name => 'Admin', :email => 'admin@locomotiveapp.org', :password => 'locomotive', :password_confirmation => 'locomotive' diff --git a/spec/factories.rb b/spec/factories.rb index dc944b06..6e5de74d 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -5,13 +5,12 @@ Factory.define :site do |s| s.created_at Time.now end -## Accounts ## -# Factory.define :account do |a| -# a.name 'Bart Simpson' -# a.email 'bart@fox.com' -# a.password 'easyone' -# a.password_confirmation 'easyone' -# a.locale 'en' -# end +# Accounts ## +Factory.define :account do |a| + a.name 'Bart Simpson' + a.email 'bart@simpson.net' + a.password 'easyone' + a.password_confirmation 'easyone' + a.locale 'en' +end -## Site ## diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb new file mode 100644 index 00000000..e94a8ace --- /dev/null +++ b/spec/models/account_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe Account do + + it 'should have a valid factory' do + Factory.build(:account).should be_valid + end + + ## Validations ## + + %w{name email password}.each do |attr| + it "should validate presence of #{attr}" do + account = Factory.build(:account, attr.to_sym => nil) + account.should_not be_valid + account.errors[attr.to_sym].should include("can't be blank") + end + end + + it "should have a default locale" do + account = Factory.build(:account, :locale => nil) + account.should be_valid + account.locale.should == 'en' + end + + it "should validate uniqueness of email" do + Factory(:account) + (account = Factory.build(:account)).should_not be_valid + account.errors[:email].should == ["is already taken"] + end + + ## Associations ## + + it 'should own many sites' do + account = Factory(:account) + site_1 = Factory(:site, :accounts => account) + site_2 = Factory(:site, :subdomain => 'foo', :accounts => account) + account.sites.should == [site_1, site_2] + end + +end \ No newline at end of file diff --git a/spec/models/site_spec.rb b/spec/models/site_spec.rb index b7dd1db5..18f6f9a4 100644 --- a/spec/models/site_spec.rb +++ b/spec/models/site_spec.rb @@ -80,6 +80,16 @@ describe Site do sites.should be_empty end + ## Associations ## + + it 'should have many accounts' do + account_1 = Factory(:account) + account_2 = Factory(:account, :name => 'homer', :email => 'homer@simpson.net') + site = Factory(:site, :accounts => [account_1, account_2, account_1]) + site.account_ids.should == [account_1.id, account_2.id] + site.accounts.should == [account_1, account_2] + end + ## Methods ## it 'should return domains without subdomain' do @@ -87,4 +97,5 @@ describe Site do site.domains.should == %w{www.acme.net www.acme.com acme.example.com} site.domains_without_subdomain.should == %w{www.acme.net www.acme.com} end + end \ No newline at end of file