Commit 63cd8feadbc85bed6946532214b5b45469e60ca7

Authored by Jared Pace
1 parent c5fbd31d
Exists in master and in 1 other branch production

WIP - Add Users backed by Devise

@@ -6,6 +6,7 @@ gem 'bson_ext', :require => nil @@ -6,6 +6,7 @@ gem 'bson_ext', :require => nil
6 gem 'mongoid', '2.0.0.beta.15' 6 gem 'mongoid', '2.0.0.beta.15'
7 gem 'haml' 7 gem 'haml'
8 gem 'will_paginate' 8 gem 'will_paginate'
  9 +gem 'devise', '1.1.1'
9 10
10 group :development, :test do 11 group :development, :test do
11 gem 'rspec-rails', '>= 2.0.0.beta.19' 12 gem 'rspec-rails', '>= 2.0.0.beta.19'
@@ -30,10 +30,14 @@ GEM @@ -30,10 +30,14 @@ GEM
30 activesupport (3.0.0.rc) 30 activesupport (3.0.0.rc)
31 arel (0.4.0) 31 arel (0.4.0)
32 activesupport (>= 3.0.0.beta) 32 activesupport (>= 3.0.0.beta)
  33 + bcrypt-ruby (2.1.2)
33 bson (1.0.4) 34 bson (1.0.4)
34 bson_ext (1.0.4) 35 bson_ext (1.0.4)
35 builder (2.1.2) 36 builder (2.1.2)
36 database_cleaner (0.5.2) 37 database_cleaner (0.5.2)
  38 + devise (1.1.1)
  39 + bcrypt-ruby (~> 2.1.2)
  40 + warden (~> 0.10.7)
37 diff-lcs (1.1.2) 41 diff-lcs (1.1.2)
38 erubis (2.6.6) 42 erubis (2.6.6)
39 abstract (>= 1.0.0) 43 abstract (>= 1.0.0)
@@ -41,7 +45,7 @@ GEM @@ -41,7 +45,7 @@ GEM
41 factory_girl_rails (1.0) 45 factory_girl_rails (1.0)
42 factory_girl (~> 1.3) 46 factory_girl (~> 1.3)
43 rails (>= 3.0.0.beta4) 47 rails (>= 3.0.0.beta4)
44 - haml (3.0.15) 48 + haml (3.0.16)
45 i18n (0.4.1) 49 i18n (0.4.1)
46 libxml-ruby (1.1.4) 50 libxml-ruby (1.1.4)
47 mail (2.2.5) 51 mail (2.2.5)
@@ -93,6 +97,8 @@ GEM @@ -93,6 +97,8 @@ GEM
93 treetop (1.4.8) 97 treetop (1.4.8)
94 polyglot (>= 0.3.1) 98 polyglot (>= 0.3.1)
95 tzinfo (0.3.22) 99 tzinfo (0.3.22)
  100 + warden (0.10.7)
  101 + rack (>= 1.0.0)
96 webrat (0.7.2.beta.1) 102 webrat (0.7.2.beta.1)
97 nokogiri (>= 1.2.0) 103 nokogiri (>= 1.2.0)
98 rack (>= 1.0) 104 rack (>= 1.0)
@@ -105,6 +111,7 @@ PLATFORMS @@ -105,6 +111,7 @@ PLATFORMS
105 DEPENDENCIES 111 DEPENDENCIES
106 bson_ext 112 bson_ext
107 database_cleaner (= 0.5.2) 113 database_cleaner (= 0.5.2)
  114 + devise (= 1.1.1)
108 factory_girl_rails 115 factory_girl_rails
109 haml 116 haml
110 libxml-ruby 117 libxml-ruby
1 Errbit: The open source self-hosted Hoptoad Server 1 Errbit: The open source self-hosted Hoptoad Server
2 ===================================================== 2 =====================================================
3 3
4 -WIP 4 +Installation
  5 +------------
5 6
6 -TODO: License  
7 \ No newline at end of file 7 \ No newline at end of file
  8 +1. Install MongoDB
  9 +2. Install & Run Bundler
  10 +3. Seed DB - rake db:seed
8 \ No newline at end of file 11 \ No newline at end of file
app/controllers/application_controller.rb
1 class ApplicationController < ActionController::Base 1 class ApplicationController < ActionController::Base
2 protect_from_forgery 2 protect_from_forgery
  3 +
  4 + before_filter :authenticate_user!
  5 +
3 end 6 end
app/mailers/mailer.rb
1 class Mailer < ActionMailer::Base 1 class Mailer < ActionMailer::Base
2 default :from => Errbit::Config.email_from 2 default :from => Errbit::Config.email_from
3 - default_url_options[:host] = Errbit::Config.host  
4 3
5 def err_notification(notice) 4 def err_notification(notice)
6 @notice = notice 5 @notice = notice
app/models/user.rb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +class User
  2 + include Mongoid::Document
  3 +
  4 + devise :database_authenticatable, :registerable,
  5 + :recoverable, :rememberable, :trackable,
  6 + :validatable, :token_authenticatable
  7 +
  8 + field :name
  9 + field :admin, :type => Boolean, :default => false
  10 +
  11 + validates_presence_of :name
  12 +
  13 +end
app/views/devise/confirmations/new.html.haml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +%h2 Resend confirmation instructions
  2 += form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f|
  3 + = devise_error_messages!
  4 + %p
  5 + = f.label :email
  6 + %br/
  7 + = f.text_field :email
  8 + %p= f.submit "Resend confirmation instructions"
  9 += render :partial => "devise/shared/links"
app/views/devise/mailer/confirmation_instructions.html.haml 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +%p
  2 + Welcome #{@resource.email}!
  3 +%p You can confirm your account through the link below:
  4 +%p= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token)
app/views/devise/mailer/reset_password_instructions.html.haml 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +%p
  2 + Hello #{@resource.email}!
  3 +%p Someone has requested a link to change your password, and you can do this through the link below.
  4 +%p= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token)
  5 +%p If you didn't request this, please ignore this email.
  6 +%p Your password won't change until you access the link above and create a new one.
app/views/devise/mailer/unlock_instructions.html.haml 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +%p
  2 + Hello #{@resource.email}!
  3 +%p Your account has been locked due to an excessive amount of unsuccessful sign in attempts.
  4 +%p Click the link below to unlock your account:
  5 +%p= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @resource.unlock_token)
app/views/devise/passwords/edit.html.haml 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +%h2 Change your password
  2 += form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f|
  3 + = devise_error_messages!
  4 + = f.hidden_field :reset_password_token
  5 + %p
  6 + = f.label :password
  7 + %br/
  8 + = f.password_field :password
  9 + %p
  10 + = f.label :password_confirmation
  11 + %br/
  12 + = f.password_field :password_confirmation
  13 + %p= f.submit "Change my password"
  14 += render :partial => "devise/shared/links"
app/views/devise/passwords/new.html.haml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +%h2 Forgot your password?
  2 += form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f|
  3 + = devise_error_messages!
  4 + %p
  5 + = f.label :email
  6 + %br/
  7 + = f.text_field :email
  8 + %p= f.submit "Send me reset password instructions"
  9 += render :partial => "devise/shared/links"
app/views/devise/registrations/edit.html.haml 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +%h2
  2 + Edit #{resource_name.to_s.humanize}
  3 += form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f|
  4 + = devise_error_messages!
  5 + %p
  6 + = f.label :email
  7 + %br/
  8 + = f.text_field :email
  9 + %p
  10 + = f.label :password
  11 + %i (leave blank if you don't want to change it)
  12 + %br/
  13 + = f.password_field :password
  14 + %p
  15 + = f.label :password_confirmation
  16 + %br/
  17 + = f.password_field :password_confirmation
  18 + %p
  19 + = f.label :current_password
  20 + %i (we need your current password to confirm your changes)
  21 + %br/
  22 + = f.password_field :current_password
  23 + %p= f.submit "Update"
  24 +%h3 Cancel my account
  25 +%p
  26 + Unhappy? #{link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete}.
  27 += link_to "Back", :back
app/views/devise/registrations/new.html.haml 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +%h2 Sign up
  2 += form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
  3 + = devise_error_messages!
  4 + %p
  5 + = f.label :name
  6 + = f.text_field :name
  7 + %p
  8 + = f.label :email
  9 + %br/
  10 + = f.text_field :email
  11 + %p
  12 + = f.label :password
  13 + %br/
  14 + = f.password_field :password
  15 + %p
  16 + = f.label :password_confirmation
  17 + %br/
  18 + = f.password_field :password_confirmation
  19 + %p= f.submit "Sign up"
  20 += render :partial => "devise/shared/links"
app/views/devise/sessions/new.html.haml 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +%h2 Sign in
  2 += form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f|
  3 + %p
  4 + = f.label :email
  5 + %br/
  6 + = f.text_field :email
  7 + %p
  8 + = f.label :password
  9 + %br/
  10 + = f.password_field :password
  11 + - if devise_mapping.rememberable?
  12 + %p
  13 + = f.check_box :remember_me
  14 + = f.label :remember_me
  15 + %p= f.submit "Sign in"
  16 += render :partial => "devise/shared/links"
app/views/devise/shared/_links.haml 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +- if controller_name != 'sessions'
  2 + = link_to "Sign in", new_session_path(resource_name)
  3 + %br/
  4 +- if devise_mapping.registerable? && controller_name != 'registrations'
  5 + = link_to "Sign up", new_registration_path(resource_name)
  6 + %br/
  7 +- if devise_mapping.recoverable? && controller_name != 'passwords'
  8 + = link_to "Forgot your password?", new_password_path(resource_name)
  9 + %br/
  10 +- if devise_mapping.confirmable? && controller_name != 'confirmations'
  11 + = link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name)
  12 + %br/
  13 +- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks'
  14 + = link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name)
  15 + %br/
app/views/devise/unlocks/new.html.haml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +%h2 Resend unlock instructions
  2 += form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f|
  3 + = devise_error_messages!
  4 + %p
  5 + = f.label :email
  6 + %br/
  7 + = f.text_field :email
  8 + %p= f.submit "Resend unlock instructions"
  9 += render :partial => "devise/shared/links"
config/initializers/_load_config.rb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +require 'ostruct'
  2 +
  3 +yaml = File.read(Rails.root.join('config','config.yml'))
  4 +config = YAML.load(yaml)
  5 +
  6 +config.merge!(config.delete(Rails.env)) if config.has_key?(Rails.env)
  7 +
  8 +Errbit::Config = OpenStruct.new(config)
  9 +
  10 +# Set config specific values
  11 +ActionMailer::Base.default_url_options[:host] = Errbit::Config.host
0 \ No newline at end of file 12 \ No newline at end of file
config/initializers/devise.rb 0 → 100644
@@ -0,0 +1,142 @@ @@ -0,0 +1,142 @@
  1 +# Use this hook to configure devise mailer, warden hooks and so forth. The first
  2 +# four configuration values can also be set straight in your models.
  3 +Devise.setup do |config|
  4 + # ==> Mailer Configuration
  5 + # Configure the e-mail address which will be shown in DeviseMailer.
  6 + config.mailer_sender = Errbit::Config.email_from
  7 +
  8 + # Configure the class responsible to send e-mails.
  9 + # config.mailer = "Devise::Mailer"
  10 +
  11 + # ==> ORM configuration
  12 + # Load and configure the ORM. Supports :active_record (default) and
  13 + # :mongoid (bson_ext recommended) by default. Other ORMs may be
  14 + # available as additional gems.
  15 + require 'devise/orm/mongoid'
  16 +
  17 + # ==> Configuration for any authentication mechanism
  18 + # Configure which keys are used when authenticating an user. By default is
  19 + # just :email. You can configure it to use [:username, :subdomain], so for
  20 + # authenticating an user, both parameters are required. Remember that those
  21 + # parameters are used only when authenticating and not when retrieving from
  22 + # session. If you need permissions, you should implement that in a before filter.
  23 + # config.authentication_keys = [ :email ]
  24 +
  25 + # Tell if authentication through request.params is enabled. True by default.
  26 + # config.params_authenticatable = true
  27 +
  28 + # Tell if authentication through HTTP Basic Auth is enabled. True by default.
  29 + # config.http_authenticatable = true
  30 +
  31 + # Set this to true to use Basic Auth for AJAX requests. True by default.
  32 + # config.http_authenticatable_on_xhr = true
  33 +
  34 + # The realm used in Http Basic Authentication
  35 + # config.http_authentication_realm = "Application"
  36 +
  37 + # ==> Configuration for :database_authenticatable
  38 + # For bcrypt, this is the cost for hashing the password and defaults to 10. If
  39 + # using other encryptors, it sets how many times you want the password re-encrypted.
  40 + config.stretches = 10
  41 +
  42 + # Define which will be the encryption algorithm. Devise also supports encryptors
  43 + # from others authentication tools as :clearance_sha1, :authlogic_sha512 (then
  44 + # you should set stretches above to 20 for default behavior) and :restful_authentication_sha1
  45 + # (then you should set stretches to 10, and copy REST_AUTH_SITE_KEY to pepper)
  46 + config.encryptor = :bcrypt
  47 +
  48 + # Setup a pepper to generate the encrypted password.
  49 + config.pepper = "425f10f555c1a4718aff3370ef9dd2d97a21622beb0400fde6b52177375ddcbe37a2dac6af9bca835c988e00c32887ee940ba111a78eab48234d8799936d36b9"
  50 +
  51 + # ==> Configuration for :confirmable
  52 + # The time you want to give your user to confirm his account. During this time
  53 + # he will be able to access your application without confirming. Default is nil.
  54 + # When confirm_within is zero, the user won't be able to sign in without confirming.
  55 + # You can use this to let your user access some features of your application
  56 + # without confirming the account, but blocking it after a certain period
  57 + # (ie 2 days).
  58 + # config.confirm_within = 2.days
  59 +
  60 + # ==> Configuration for :rememberable
  61 + # The time the user will be remembered without asking for credentials again.
  62 + config.remember_for = 2.weeks
  63 +
  64 + # If true, a valid remember token can be re-used between multiple browsers.
  65 + # config.remember_across_browsers = true
  66 +
  67 + # If true, extends the user's remember period when remembered via cookie.
  68 + # config.extend_remember_period = false
  69 +
  70 + # ==> Configuration for :validatable
  71 + # Range for password length
  72 + config.password_length = 6..20
  73 +
  74 + # Regex to use to validate the email address
  75 + config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
  76 +
  77 + # ==> Configuration for :timeoutable
  78 + # The time you want to timeout the user session without activity. After this
  79 + # time the user will be asked for credentials again.
  80 + # config.timeout_in = 10.minutes
  81 +
  82 + # ==> Configuration for :lockable
  83 + # Defines which strategy will be used to lock an account.
  84 + # :failed_attempts = Locks an account after a number of failed attempts to sign in.
  85 + # :none = No lock strategy. You should handle locking by yourself.
  86 + # config.lock_strategy = :failed_attempts
  87 +
  88 + # Defines which strategy will be used to unlock an account.
  89 + # :email = Sends an unlock link to the user email
  90 + # :time = Re-enables login after a certain amount of time (see :unlock_in below)
  91 + # :both = Enables both strategies
  92 + # :none = No unlock strategy. You should handle unlocking by yourself.
  93 + # config.unlock_strategy = :both
  94 +
  95 + # Number of authentication tries before locking an account if lock_strategy
  96 + # is failed attempts.
  97 + # config.maximum_attempts = 20
  98 +
  99 + # Time interval to unlock the account if :time is enabled as unlock_strategy.
  100 + # config.unlock_in = 1.hour
  101 +
  102 + # ==> Configuration for :token_authenticatable
  103 + # Defines name of the authentication token params key
  104 + config.token_authentication_key = :auth_token
  105 +
  106 + # ==> Scopes configuration
  107 + # Turn scoped views on. Before rendering "sessions/new", it will first check for
  108 + # "users/sessions/new". It's turned off by default because it's slower if you
  109 + # are using only default views.
  110 + # config.scoped_views = true
  111 +
  112 + # Configure the default scope given to Warden. By default it's the first
  113 + # devise role declared in your routes.
  114 + # config.default_scope = :user
  115 +
  116 + # Configure sign_out behavior.
  117 + # By default sign_out is scoped (i.e. /users/sign_out affects only :user scope).
  118 + # In case of sign_out_all_scopes set to true any logout action will sign out all active scopes.
  119 + # config.sign_out_all_scopes = false
  120 +
  121 + # ==> Navigation configuration
  122 + # Lists the formats that should be treated as navigational. Formats like
  123 + # :html, should redirect to the sign in page when the user does not have
  124 + # access, but formats like :xml or :json, should return 401.
  125 + # If you have any extra navigational formats, like :iphone or :mobile, you
  126 + # should add them to the navigational formats lists. Default is [:html]
  127 + # config.navigational_formats = [:html, :iphone]
  128 +
  129 + # ==> Warden configuration
  130 + # If you want to use other strategies, that are not (yet) supported by Devise,
  131 + # you can configure them inside the config.warden block. The example below
  132 + # allows you to setup OAuth, using http://github.com/roman/warden_oauth
  133 + #
  134 + # config.warden do |manager|
  135 + # manager.oauth(:twitter) do |twitter|
  136 + # twitter.consumer_secret = <YOUR CONSUMER SECRET>
  137 + # twitter.consumer_key = <YOUR CONSUMER KEY>
  138 + # twitter.options :site => 'http://twitter.com'
  139 + # end
  140 + # manager.default_strategies(:scope => :user).unshift :twitter_oauth
  141 + # end
  142 +end
config/initializers/load_config.rb
@@ -1,8 +0,0 @@ @@ -1,8 +0,0 @@
1 -require 'ostruct'  
2 -  
3 -yaml = File.read(Rails.root.join('config','config.yml'))  
4 -config = YAML.load(yaml)  
5 -  
6 -config.merge!(config.delete(Rails.env)) if config.has_key?(Rails.env)  
7 -  
8 -Errbit::Config = OpenStruct.new(config)  
9 \ No newline at end of file 0 \ No newline at end of file
config/locales/devise.en.yml 0 → 100644
@@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
  1 +en:
  2 + errors:
  3 + messages:
  4 + not_found: "not found"
  5 + already_confirmed: "was already confirmed"
  6 + not_locked: "was not locked"
  7 +
  8 + devise:
  9 + failure:
  10 + unauthenticated: 'You need to sign in or sign up before continuing.'
  11 + unconfirmed: 'You have to confirm your account before continuing.'
  12 + locked: 'Your account is locked.'
  13 + invalid: 'Invalid email or password.'
  14 + invalid_token: 'Invalid authentication token.'
  15 + timeout: 'Your session expired, please sign in again to continue.'
  16 + inactive: 'Your account was not activated yet.'
  17 + sessions:
  18 + signed_in: 'Signed in successfully.'
  19 + signed_out: 'Signed out successfully.'
  20 + passwords:
  21 + send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
  22 + updated: 'Your password was changed successfully. You are now signed in.'
  23 + confirmations:
  24 + send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
  25 + confirmed: 'Your account was successfully confirmed. You are now signed in.'
  26 + registrations:
  27 + signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.'
  28 + updated: 'You updated your account successfully.'
  29 + destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
  30 + unlocks:
  31 + send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
  32 + unlocked: 'Your account was successfully unlocked. You are now signed in.'
  33 + mailer:
  34 + confirmation_instructions:
  35 + subject: 'Confirmation instructions'
  36 + reset_password_instructions:
  37 + subject: 'Reset password instructions'
  38 + unlock_instructions:
  39 + subject: 'Unlock Instructions'
config/routes.rb
1 Errbit::Application.routes.draw do 1 Errbit::Application.routes.draw do
2 2
  3 + devise_for :users
  4 +
3 # Hoptoad Notifier Routes 5 # Hoptoad Notifier Routes
4 match '/notifier_api/v2/notices' => 'notices#create' 6 match '/notifier_api/v2/notices' => 'notices#create'
5 match '/deploys.txt' => 'deploys#create' 7 match '/deploys.txt' => 'deploys#create'
@@ -21,6 +23,8 @@ Errbit::Application.routes.draw do @@ -21,6 +23,8 @@ Errbit::Application.routes.draw do
21 end 23 end
22 end 24 end
23 25
  26 + devise_for :users
  27 +
24 root :to => 'apps#index' 28 root :to => 'apps#index'
25 29
26 end 30 end
1 -# This file should contain all the record creation needed to seed the database with its default values.  
2 -# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).  
3 -#  
4 -# Examples:  
5 -#  
6 -# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])  
7 -# Mayor.create(:name => 'Daley', :city => cities.first) 1 +# Create an initial Admin User
  2 +admin_email = "errbit@#{Errbit::Config.host}"
  3 +admin_pass = 'password'
  4 +
  5 +puts "Creating an initial admin user:"
  6 +puts "-- email: #{admin_email}"
  7 +puts "-- password: #{admin_pass}"
  8 +puts ""
  9 +puts "Be sure to change these credentials ASAP!"
  10 +User.create!({
  11 + :name => 'Errbit Admin',
  12 + :email => admin_email,
  13 + :password => admin_pass,
  14 + :password_confirmation => admin_pass,
  15 + :admin => true
  16 +})
8 \ No newline at end of file 17 \ No newline at end of file
spec/models/user_spec.rb 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +require 'spec_helper'
  2 +
  3 +describe User do
  4 + pending "add some examples to (or delete) #{__FILE__}"
  5 +end