Commit 63cd8feadbc85bed6946532214b5b45469e60ca7
1 parent
c5fbd31d
Exists in
master
and in
1 other branch
WIP - Add Users backed by Devise
Showing
24 changed files
with
381 additions
and
19 deletions
Show diff stats
Gemfile
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
app/mailers/mailer.rb
| ... | ... | @@ -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 | ... | ... |
| ... | ... | @@ -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
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. | ... | ... |
| ... | ... | @@ -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) | ... | ... |
| ... | ... | @@ -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" | ... | ... |
| ... | ... | @@ -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" | ... | ... |
| ... | ... | @@ -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 | ... | ... |
| ... | ... | @@ -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" | ... | ... |
| ... | ... | @@ -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" | ... | ... |
| ... | ... | @@ -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/ | ... | ... |
| ... | ... | @@ -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" | ... | ... |
| ... | ... | @@ -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 | ... | ... |
| ... | ... | @@ -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
| ... | ... | @@ -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 | ... | ... |