diff --git a/app/controllers/admin/auth_controller.rb b/app/controllers/admin/auth_controller.rb index a6db502..fa19122 100644 --- a/app/controllers/admin/auth_controller.rb +++ b/app/controllers/admin/auth_controller.rb @@ -21,5 +21,44 @@ module Admin reset_session redirect_to admin_login_path end + + def reset_request + end + + def send_reset + user = User.find_by(email: request_params[:email]) + redirect_to(admin_reset_request_path) and return if user.nil? + + user.setup_reset + # TODO: user mailer deliver_now + redirect_to admin_reset_request_path, + success: "Reset request sent! Please check your email for instructions." + end + + def reset + user = User.find_by(reset_token: params[:reset_token]) + redirect_to(admin_reset_request_path) and return if user.nil? + end + + def reset_password + user = User.find_by(reset_token: params[:reset_token]) + redirect_to(admin_reset_request_path) and return if user.nil? + + if user.update(reset_params) + redirect_to admin_login_path, success: "Password has been reset. Please log in." + else + redirect_to(admin_reset_request_path) + end + end + + private + + def request_params + params.require(:auth).permit(:email) + end + + def reset_params + params.require(:auth).permit(:password, :password_confirmation) + end end end diff --git a/app/controllers/admin/profile_controller.rb b/app/controllers/admin/profile_controller.rb index 7fc32c9..08f8f32 100644 --- a/app/controllers/admin/profile_controller.rb +++ b/app/controllers/admin/profile_controller.rb @@ -19,7 +19,10 @@ module Admin end end - def lost_password + private + + def user_params + params.require(:user).permit(:name, :email, :password, :password_confirmation) end end end diff --git a/app/models/user.rb b/app/models/user.rb index 1da0679..781cfac 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,4 +5,20 @@ class User < ApplicationRecord validates_presence_of :email validates_presence_of :name validates_presence_of :role + validates :reset_token, uniqueness: true, allow_nil: true + + def setup_reset + gen_reset_token + save + end + + private + + def gen_reset_token + loop do + self[:reset_token] = SecureRandom.urlsafe_base64(10) + self[:reset_timestamp] = DateTime.now + break unless User.exists?(reset_token: self[:reset_token]) + end + end end diff --git a/app/views/admin/auth/login.html.erb b/app/views/admin/auth/login.html.erb index 3850506..725a817 100644 --- a/app/views/admin/auth/login.html.erb +++ b/app/views/admin/auth/login.html.erb @@ -4,10 +4,6 @@

Admin Login

-<% if flash[:error].present? %> -
<%= flash[:error] %>
-<% end %> - <%= form_for :auth, url: admin_login_path do |form| %>
<%= form.label :email %> diff --git a/app/views/admin/auth/reset.html.erb b/app/views/admin/auth/reset.html.erb new file mode 100644 index 0000000..2b1aee8 --- /dev/null +++ b/app/views/admin/auth/reset.html.erb @@ -0,0 +1,21 @@ +<% + content_for :main_class, "intro_tpl" +%> + +

Password Reset

+ +<%= form_for :auth, url: admin_reset_password_path do |form| %> + <%= hidden_field_tag :reset_token, params[:reset_token] %> + +
+ <%= form.label :password %> + <%= form.password_field :password %> +
+ +
+ <%= form.label :password_confirmation %> + <%= form.password_field :password_confirmation %> +
+ + <%= submit_tag "Reset Password" %> +<% end %> diff --git a/app/views/admin/auth/reset_request.html.erb b/app/views/admin/auth/reset_request.html.erb new file mode 100644 index 0000000..7e3975b --- /dev/null +++ b/app/views/admin/auth/reset_request.html.erb @@ -0,0 +1,17 @@ +<% + content_for :main_class, "intro_tpl" +%> + +

Password Reset

+ +<%= raw(ap User.find_by(email: 'alan.admin@mailinator.com')) %> + +<%= form_for :auth, url: admin_send_reset_path do |form| %> + +
+ <%= form.label :email %> + <%= form.email_field :email %> +
+ + <%= submit_tag "Request Password Reset" %> +<% end %> diff --git a/app/views/admin/profile/lost_password.html.erb b/app/views/admin/profile/lost_password.html.erb deleted file mode 100644 index 2570697..0000000 --- a/app/views/admin/profile/lost_password.html.erb +++ /dev/null @@ -1,2 +0,0 @@ -

Admin::Profile#lost_password

-

Find me in app/views/admin/profile/lost_password.html.erb

diff --git a/config/routes.rb b/config/routes.rb index 7a07a31..3383a54 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,11 @@ Rails.application.routes.draw do - post "/admin/login", to: "admin/auth#auth", as: :admin_auth - get "/admin/login", to: "admin/auth#login", as: :admin_login - get "/admin/logout", to: "admin/auth#logout", as: :admin_logout + post "/admin/login", to: "admin/auth#auth", as: :admin_auth + get "/admin/login", to: "admin/auth#login", as: :admin_login + get "/admin/logout", to: "admin/auth#logout", as: :admin_logout + get "/admin/reset/:reset_token", to: "admin/auth#reset", as: :admin_reset + post "/admin/reset", to: "admin/auth#reset_password", as: :admin_reset_password + get "/admin/reset_request", to: "admin/auth#reset_request", as: :admin_reset_request + post "/admin/reset_request", to: "admin/auth#send_reset", as: :admin_send_reset get "/admin/quizzes", to: "admin/quiz#index", as: :admin_quizzes get "/admin/quiz/new", to: "admin/quiz#new", as: :admin_new_quiz @@ -28,10 +32,9 @@ Rails.application.routes.draw do post "/admin/question/:question_id/edit", to: "admin/question#update", as: :admin_update_question patch "/admin/question/:question_id/edit", to: "admin/question#update" - get "/admin/profile", to: "admin/profile#view", as: :admin_profile - post "/admin/profile", to: "admin/profile#update", as: :admin_update_profile - get "/admin/profile/edit", to: "admin/profile#edit", as: :admin_edit_profile - get "/admin/profile/reset", to: "admin/profile#lost_password", as: :admin_reset_password + get "/admin/profile", to: "admin/profile#view", as: :admin_profile + post "/admin/profile", to: "admin/profile#update", as: :admin_update_profile + get "/admin/profile/edit", to: "admin/profile#edit", as: :admin_edit_profile get "/admin", to: "admin#dashboard", as: :admin diff --git a/db/migrate/20160824183159_add_resets_to_users.rb b/db/migrate/20160824183159_add_resets_to_users.rb new file mode 100644 index 0000000..da9f93b --- /dev/null +++ b/db/migrate/20160824183159_add_resets_to_users.rb @@ -0,0 +1,8 @@ +class AddResetsToUsers < ActiveRecord::Migration[5.0] + def change + add_column :users, :reset_token, :string + add_column :users, :reset_timestamp, :datetime + + add_index :users, :reset_token + end +end diff --git a/db/schema.rb b/db/schema.rb index 2085033..2964332 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160818225721) do +ActiveRecord::Schema.define(version: 20160824183159) do create_table "answers", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t| t.integer "candidate_id" @@ -73,6 +73,9 @@ ActiveRecord::Schema.define(version: 20160818225721) do t.boolean "active" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "reset_token" + t.datetime "reset_timestamp" + t.index ["reset_token"], name: "index_users_on_reset_token", using: :btree end end diff --git a/test/controllers/admin/auth_controller_test.rb b/test/controllers/admin/auth_controller_test.rb index 1c22fce..d482c2c 100644 --- a/test/controllers/admin/auth_controller_test.rb +++ b/test/controllers/admin/auth_controller_test.rb @@ -36,5 +36,42 @@ module Admin assert_redirected_to admin_login_url assert_match(/incorrect.*email/, flash[:error]) end + + test "should get reset_request" do + get admin_reset_request_url + assert_response :success + end + + test "should process a reset request" do + user = users(:admin) + post admin_send_reset_url, params: { auth: { email: user.email } } + + refute_equal user.reset_token, User.find(user.id).reset_token + assert_redirected_to admin_reset_request_url + assert_match(/request.*sent/i, flash[:success]) + end + + test "should redirect with invalid reset_token" do + get admin_reset_url('fooBarBaz') + assert_redirected_to admin_reset_request_url + end + + test "should get reset form" do + user = users(:admin) + user.setup_reset + get admin_reset_url(user.reset_token) + assert :success + end + + test "should post password reset" do + user = users(:admin) + user.setup_reset + + post admin_reset_password_url, params: { auth: + { reset_token: user.reset_token, password: '12345', password_confirmation: '12345' } } + + assert_redirected_to admin_auth_path + assert_match(/reset.*log/i, flash[:success]) + end end end diff --git a/test/controllers/admin/profile_controller_test.rb b/test/controllers/admin/profile_controller_test.rb index f4f673f..aaf048f 100644 --- a/test/controllers/admin/profile_controller_test.rb +++ b/test/controllers/admin/profile_controller_test.rb @@ -22,10 +22,5 @@ module Admin assert_redirected_to admin_profile_url assert flash[:success] end - - test "should get lost_password" do - get admin_reset_password_url - assert_response :success - end end end