Commit 63cd8feadbc85bed6946532214b5b45469e60ca7

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

WIP - Add Users backed by Devise

Gemfile
... ... @@ -6,6 +6,7 @@ gem 'bson_ext', :require => nil
6 6 gem 'mongoid', '2.0.0.beta.15'
7 7 gem 'haml'
8 8 gem 'will_paginate'
  9 +gem 'devise', '1.1.1'
9 10  
10 11 group :development, :test do
11 12 gem 'rspec-rails', '>= 2.0.0.beta.19'
... ...
Gemfile.lock
... ... @@ -30,10 +30,14 @@ GEM
30 30 activesupport (3.0.0.rc)
31 31 arel (0.4.0)
32 32 activesupport (>= 3.0.0.beta)
  33 + bcrypt-ruby (2.1.2)
33 34 bson (1.0.4)
34 35 bson_ext (1.0.4)
35 36 builder (2.1.2)
36 37 database_cleaner (0.5.2)
  38 + devise (1.1.1)
  39 + bcrypt-ruby (~> 2.1.2)
  40 + warden (~> 0.10.7)
37 41 diff-lcs (1.1.2)
38 42 erubis (2.6.6)
39 43 abstract (>= 1.0.0)
... ... @@ -41,7 +45,7 @@ GEM
41 45 factory_girl_rails (1.0)
42 46 factory_girl (~> 1.3)
43 47 rails (>= 3.0.0.beta4)
44   - haml (3.0.15)
  48 + haml (3.0.16)
45 49 i18n (0.4.1)
46 50 libxml-ruby (1.1.4)
47 51 mail (2.2.5)
... ... @@ -93,6 +97,8 @@ GEM
93 97 treetop (1.4.8)
94 98 polyglot (>= 0.3.1)
95 99 tzinfo (0.3.22)
  100 + warden (0.10.7)
  101 + rack (>= 1.0.0)
96 102 webrat (0.7.2.beta.1)
97 103 nokogiri (>= 1.2.0)
98 104 rack (>= 1.0)
... ... @@ -105,6 +111,7 @@ PLATFORMS
105 111 DEPENDENCIES
106 112 bson_ext
107 113 database_cleaner (= 0.5.2)
  114 + devise (= 1.1.1)
108 115 factory_girl_rails
109 116 haml
110 117 libxml-ruby
... ...
README.md
1 1 Errbit: The open source self-hosted Hoptoad Server
2 2 =====================================================
3 3  
4   -WIP
  4 +Installation
  5 +------------
5 6  
6   -TODO: License
7 7 \ No newline at end of file
  8 +1. Install MongoDB
  9 +2. Install & Run Bundler
  10 +3. Seed DB - rake db:seed
8 11 \ No newline at end of file
... ...
app/controllers/application_controller.rb
1 1 class ApplicationController < ActionController::Base
2 2 protect_from_forgery
  3 +
  4 + before_filter :authenticate_user!
  5 +
3 6 end
... ...
app/mailers/mailer.rb
1 1 class Mailer < ActionMailer::Base
2 2 default :from => Errbit::Config.email_from
3   - default_url_options[:host] = Errbit::Config.host
4 3  
5 4 def err_notification(notice)
6 5 @notice = notice
... ...
app/models/user.rb 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 12 \ No newline at end of file
... ...
config/initializers/devise.rb 0 → 100644
... ... @@ -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   -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 0 \ No newline at end of file
config/locales/devise.en.yml 0 → 100644
... ... @@ -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 1 Errbit::Application.routes.draw do
2 2  
  3 + devise_for :users
  4 +
3 5 # Hoptoad Notifier Routes
4 6 match '/notifier_api/v2/notices' => 'notices#create'
5 7 match '/deploys.txt' => 'deploys#create'
... ... @@ -21,6 +23,8 @@ Errbit::Application.routes.draw do
21 23 end
22 24 end
23 25  
  26 + devise_for :users
  27 +
24 28 root :to => 'apps#index'
25 29  
26 30 end
... ...
db/seeds.rb
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 17 \ No newline at end of file
... ...
spec/models/user_spec.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +require 'spec_helper'
  2 +
  3 +describe User do
  4 + pending "add some examples to (or delete) #{__FILE__}"
  5 +end
... ...