Init version pf password reset.
This commit is contained in:
parent
81a5e0537d
commit
a2e5adc4c7
9 changed files with 253 additions and 12 deletions
|
@ -0,0 +1,67 @@
|
|||
$ = jQuery.sub()
|
||||
|
||||
class Index extends App.Controller
|
||||
className: 'container'
|
||||
|
||||
events:
|
||||
'submit form': 'submit',
|
||||
'click .submit': 'submit',
|
||||
'click .cancel': 'cancel',
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# set title
|
||||
@title 'Reset Password'
|
||||
@navupdate '#reset_password'
|
||||
|
||||
@render()
|
||||
|
||||
render: ->
|
||||
|
||||
configure_attributes = [
|
||||
{ name: 'username', display: 'Enter your username or email address:', tag: 'input', type: 'text', limit: 100, null: false, class: 'input span4', },
|
||||
]
|
||||
|
||||
@html App.view('reset_password')(
|
||||
form: @formGen( model: { configure_attributes: configure_attributes } ),
|
||||
)
|
||||
|
||||
cancel: ->
|
||||
@navigate 'login'
|
||||
|
||||
submit: (e) ->
|
||||
@log 'submit'
|
||||
e.preventDefault()
|
||||
params = @formParam(e.target)
|
||||
|
||||
# get data
|
||||
ajax = new App.Ajax
|
||||
ajax.ajax(
|
||||
type: 'POST',
|
||||
url: '/users/password_reset',
|
||||
data: JSON.stringify(params),
|
||||
processData: true,
|
||||
success: @success
|
||||
)
|
||||
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
@html App.view('reset_password_sent')()
|
||||
|
||||
error: (xhr, statusText, error) =>
|
||||
|
||||
# add notify
|
||||
Spine.trigger 'notify:removeall'
|
||||
Spine.trigger 'notify', {
|
||||
type: 'warning',
|
||||
msg: 'Wrong Username and Password combination.',
|
||||
}
|
||||
|
||||
# rerender login page
|
||||
@render(
|
||||
msg: 'Wrong Username and Password combination.',
|
||||
username: @username
|
||||
)
|
||||
|
||||
Config.Routes['reset_password'] = Index
|
|
@ -14,7 +14,7 @@
|
|||
<div>
|
||||
<span class="small"><input name="remember_me" value="1" type="checkbox"/> Remember me</span>
|
||||
<span class="small">·</span>
|
||||
<a href="#resend_password" class="small">Forgot password?</a>
|
||||
<a href="#reset_password" class="small">Forgot password?</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
13
app/assets/javascripts/app/views/reset_password.jst.eco
Normal file
13
app/assets/javascripts/app/views/reset_password.jst.eco
Normal file
|
@ -0,0 +1,13 @@
|
|||
<div class="hero-unit">
|
||||
<h2>Forgot your password?<small></small></h2>
|
||||
|
||||
<div class="container">
|
||||
<form>
|
||||
<p>
|
||||
<%- @form %>
|
||||
</p>
|
||||
<a href="#/" class="btn cancel">Cancel</a>
|
||||
<button class="btn btn-primary submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,9 @@
|
|||
<div class="hero-unit">
|
||||
<h2>We've sent password reset instructions to your email address.<small></small></h2>
|
||||
|
||||
<div class="container">
|
||||
<p>
|
||||
If you don't receive instructions within a minute or two, check your email's spam and junk filters, or try <a href="#reset_password">resending your request</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
|
@ -1,5 +1,5 @@
|
|||
class UsersController < ApplicationController
|
||||
before_filter :authentication_check, :except => [:create]
|
||||
before_filter :authentication_check, :except => [:create, :password_reset_send, :password_reset_verify]
|
||||
|
||||
# GET /users
|
||||
def index
|
||||
|
@ -98,4 +98,26 @@ class UsersController < ApplicationController
|
|||
|
||||
head :ok
|
||||
end
|
||||
|
||||
# POST /users/reset_password
|
||||
def password_reset_send
|
||||
puts params.inspect
|
||||
success = User.password_reset_send( params[:username] )
|
||||
if success
|
||||
render :json => { :message => 'ok' }, :status => :ok
|
||||
else
|
||||
render :json => { :message => 'failed' }, :status => :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
# get /users/verify_password/:hash
|
||||
def password_reset_verify
|
||||
success = User.password_reset_verify( params[:hash] )
|
||||
if success
|
||||
render :json => { :message => 'ok' }, :status => :ok
|
||||
else
|
||||
render :json => { :message => 'failed' }, :status => :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
31
app/models/token.rb
Normal file
31
app/models/token.rb
Normal file
|
@ -0,0 +1,31 @@
|
|||
class Token < ActiveRecord::Base
|
||||
before_create :generate_token
|
||||
|
||||
belongs_to :user
|
||||
|
||||
def self.check( data )
|
||||
|
||||
# fetch token
|
||||
token = Token.where( :action => data[:action], :name => data[:name] ).first
|
||||
return if !token
|
||||
|
||||
# check if token is still valid
|
||||
if token.created_at < 1.day.ago
|
||||
|
||||
# delete token
|
||||
token.delete
|
||||
token.save
|
||||
return
|
||||
end
|
||||
|
||||
# return token if valid
|
||||
return token
|
||||
end
|
||||
|
||||
private
|
||||
def generate_token
|
||||
begin
|
||||
self.name = SecureRandom.hex(20)
|
||||
end while Token.exists?( :name => self.name )
|
||||
end
|
||||
end
|
|
@ -8,6 +8,7 @@ class User < ApplicationModel
|
|||
has_and_belongs_to_many :groups, :after_add => :cache_update, :after_remove => :cache_update
|
||||
has_and_belongs_to_many :roles, :after_add => :cache_update, :after_remove => :cache_update
|
||||
has_and_belongs_to_many :organizations, :after_add => :cache_update, :after_remove => :cache_update
|
||||
has_many :tokens, :after_add => :cache_update, :after_remove => :cache_update
|
||||
has_many :authorizations, :after_add => :cache_update, :after_remove => :cache_update
|
||||
belongs_to :organization, :class_name => 'Organization'
|
||||
|
||||
|
@ -47,7 +48,7 @@ class User < ApplicationModel
|
|||
url = hash['info']['urls']['Website'] || hash['info']['urls']['Twitter'] || ''
|
||||
end
|
||||
roles = Role.where( :name => 'Customer' )
|
||||
create(
|
||||
self.create(
|
||||
:login => hash['info']['nickname'] || hash['uid'],
|
||||
:firstname => hash['info']['name'],
|
||||
:email => hash['info']['email'],
|
||||
|
@ -61,6 +62,85 @@ class User < ApplicationModel
|
|||
|
||||
end
|
||||
|
||||
def self.password_reset_send(username)
|
||||
puts '2'+username.inspect
|
||||
return if !username || username == ''
|
||||
|
||||
# try to find user based on login
|
||||
user = User.where( :login => username, :active => true ).first
|
||||
|
||||
# try second lookup with email
|
||||
if !user
|
||||
user = User.where( :email => username, :active => true ).first
|
||||
end
|
||||
|
||||
# check if email address exists
|
||||
return if !user.email
|
||||
|
||||
# generate token
|
||||
token = Token.create( :action => 'PasswordReset', :user_id => user.id )
|
||||
|
||||
# send mail
|
||||
data = {}
|
||||
data[:subject] = 'Reset your #{config.product_name} password'
|
||||
data[:body] = 'Forgot your password?
|
||||
|
||||
We received a request to reset the password for your #{config.product_name} account (#{user.login}).
|
||||
|
||||
If you want to reset your password, click on the link below (or copy and paste the URL into your browser):
|
||||
|
||||
#{config.http_type}://#{config.fqdn}/password_reset_verify/#{token.name}
|
||||
|
||||
This link takes you to a page where you can change your password.
|
||||
|
||||
If you don\'t want to reset your password, please ignore this message. Your password will not be reset.
|
||||
|
||||
Your #{config.product_name} Team
|
||||
'
|
||||
|
||||
# prepare subject & body
|
||||
[:subject, :body].each { |key|
|
||||
data[key.to_sym] = NotificationFactory.build(
|
||||
:string => data[key.to_sym],
|
||||
:objects => {
|
||||
:token => token,
|
||||
:user => user,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
# send notification
|
||||
NotificationFactory.send(
|
||||
:recipient => user,
|
||||
:subject => data[:subject],
|
||||
:body => data[:body]
|
||||
)
|
||||
return true
|
||||
end
|
||||
|
||||
def self.password_reset_check(token)
|
||||
|
||||
# check token
|
||||
token = Token.check( :action => 'PasswordReset', :name => token )
|
||||
return if !token
|
||||
return true
|
||||
end
|
||||
|
||||
def self.password_reset_via_token(token,password)
|
||||
|
||||
# check token
|
||||
token = Token.check( :action => 'PasswordReset', :name => token )
|
||||
return if !token
|
||||
|
||||
# reset password
|
||||
token.user.update_attributes( :password => password )
|
||||
|
||||
# delete token
|
||||
token.delete
|
||||
token.save
|
||||
return true
|
||||
end
|
||||
|
||||
def self.find_fulldata(user_id)
|
||||
|
||||
return cache_get(user_id) if cache_get(user_id)
|
||||
|
|
|
@ -14,6 +14,8 @@ Zammad::Application.routes.draw do
|
|||
# base objects
|
||||
resources :settings, :only => [:create, :show, :index, :update]
|
||||
resources :users, :only => [:create, :show, :index, :update]
|
||||
match '/users/password_reset', :to => 'users#password_reset_send'
|
||||
match '/users/password_reset_verify', :to => 'users#password_reset_verify'
|
||||
resources :groups, :only => [:create, :show, :index, :update]
|
||||
resources :roles, :only => [:create, :show, :index, :update]
|
||||
resources :organizations, :only => [:create, :show, :index, :update]
|
||||
|
|
17
db/migrate/20120101000080_create_token.rb
Normal file
17
db/migrate/20120101000080_create_token.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
class CreateToken < ActiveRecord::Migration
|
||||
def up
|
||||
create_table :tokens do |t|
|
||||
t.references :user, :null => false
|
||||
t.string :name, :limit => 100, :null => false
|
||||
t.string :action, :limit => 40, :null => false
|
||||
t.timestamps
|
||||
end
|
||||
add_index :tokens, :user_id
|
||||
add_index :tokens, [:name, :action], :unique => true
|
||||
add_index :tokens, :created_at
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :tokens
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue