Added email verify feature for self signup accounts.
This commit is contained in:
parent
2ac873886e
commit
5adba8c9d0
14 changed files with 405 additions and 50 deletions
|
@ -223,7 +223,7 @@ class App.Controller extends Spine.Controller
|
||||||
# remember requested url
|
# remember requested url
|
||||||
if !checkOnly
|
if !checkOnly
|
||||||
location = window.location.hash
|
location = window.location.hash
|
||||||
if location isnt '#login' && location isnt '#logout' && location isnt '#keyboard_shortcuts'
|
if location && location isnt '#login' && location isnt '#logout' && location isnt '#keyboard_shortcuts'
|
||||||
@Config.set('requested_url', location)
|
@Config.set('requested_url', location)
|
||||||
|
|
||||||
return false if checkOnly
|
return false if checkOnly
|
||||||
|
@ -559,16 +559,20 @@ class App.Controller extends Spine.Controller
|
||||||
return if !@initLoadingDoneDelay
|
return if !@initLoadingDoneDelay
|
||||||
@clearDelay(@initLoadingDoneDelay)
|
@clearDelay(@initLoadingDoneDelay)
|
||||||
|
|
||||||
|
renderScreenSuccess: (data) ->
|
||||||
|
App.TaskManager.touch(@task_key) if @task_key
|
||||||
|
@html App.view('generic/error/success')(data)
|
||||||
|
|
||||||
renderScreenError: (data) ->
|
renderScreenError: (data) ->
|
||||||
App.TaskManager.touch(@task_key)
|
App.TaskManager.touch(@task_key) if @task_key
|
||||||
@html App.view('generic/error/generic')(data)
|
@html App.view('generic/error/generic')(data)
|
||||||
|
|
||||||
renderScreenNotFound: (data) ->
|
renderScreenNotFound: (data) ->
|
||||||
App.TaskManager.touch(@task_key)
|
App.TaskManager.touch(@task_key) if @task_key
|
||||||
@html App.view('generic/error/not_found')(data)
|
@html App.view('generic/error/not_found')(data)
|
||||||
|
|
||||||
renderScreenUnauthorized: (data) ->
|
renderScreenUnauthorized: (data) ->
|
||||||
App.TaskManager.touch(@task_key)
|
App.TaskManager.touch(@task_key) if @task_key
|
||||||
@html App.view('generic/error/unauthorized')(data)
|
@html App.view('generic/error/unauthorized')(data)
|
||||||
|
|
||||||
locationVerify: (e) =>
|
locationVerify: (e) =>
|
||||||
|
|
|
@ -28,5 +28,5 @@ class DefaultRouter extends App.Controller
|
||||||
|
|
||||||
@navigate '#dashboard', true
|
@navigate '#dashboard', true
|
||||||
|
|
||||||
App.Config.set( '', DefaultRouter, 'Routes' )
|
App.Config.set('', DefaultRouter, 'Routes')
|
||||||
App.Config.set( '/', DefaultRouter, 'Routes' )
|
App.Config.set('/', DefaultRouter, 'Routes')
|
||||||
|
|
55
app/assets/javascripts/app/controllers/email_verify.coffee
Normal file
55
app/assets/javascripts/app/controllers/email_verify.coffee
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
class Index extends App.Controller
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
return if !@authenticate()
|
||||||
|
@verifyCall()
|
||||||
|
|
||||||
|
verifyCall: =>
|
||||||
|
@ajax(
|
||||||
|
id: 'email_verify'
|
||||||
|
type: 'POST'
|
||||||
|
url: @apiPath + '/users/email_verify'
|
||||||
|
data: JSON.stringify(token: @token)
|
||||||
|
processData: true
|
||||||
|
success: @success
|
||||||
|
error: @error
|
||||||
|
)
|
||||||
|
|
||||||
|
success: =>
|
||||||
|
new Success(el: @el)
|
||||||
|
|
||||||
|
error: =>
|
||||||
|
new Fail(el: @el)
|
||||||
|
|
||||||
|
class Success extends App.ControllerContent
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
@render()
|
||||||
|
|
||||||
|
# rerender view, e. g. on language change
|
||||||
|
@bind 'ui:rerender', =>
|
||||||
|
@render()
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
@renderScreenSuccess(
|
||||||
|
detail: 'Woo hoo! Your email is verified!'
|
||||||
|
)
|
||||||
|
delay = =>
|
||||||
|
@navigate '#'
|
||||||
|
@delay(delay, 20500)
|
||||||
|
|
||||||
|
class Fail extends App.ControllerContent
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
@render()
|
||||||
|
|
||||||
|
# rerender view, e. g. on language change
|
||||||
|
@bind 'ui:rerender', =>
|
||||||
|
@render()
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
@renderScreenError(
|
||||||
|
detail: 'Unable to verify email. Please contact your administrator.'
|
||||||
|
)
|
||||||
|
|
||||||
|
App.Config.set('email_verify/:token', Index, 'Routes')
|
|
@ -136,4 +136,4 @@ class Index extends App.ControllerContent
|
||||||
600
|
600
|
||||||
)
|
)
|
||||||
|
|
||||||
App.Config.set( 'login', Index, 'Routes' )
|
App.Config.set('login', Index, 'Routes')
|
||||||
|
|
|
@ -64,8 +64,8 @@ class Index extends App.ControllerContent
|
||||||
if data.token && @Config.get('developer_mode') is true
|
if data.token && @Config.get('developer_mode') is true
|
||||||
redirect = =>
|
redirect = =>
|
||||||
@navigate "#password_reset_verify/#{data.token}"
|
@navigate "#password_reset_verify/#{data.token}"
|
||||||
@delay( redirect, 2000 )
|
@delay(redirect, 2000)
|
||||||
@render( sent: true )
|
@render(sent: true)
|
||||||
|
|
||||||
else
|
else
|
||||||
@$('[name=username]').val('')
|
@$('[name=username]').val('')
|
||||||
|
@ -75,7 +75,7 @@ class Index extends App.ControllerContent
|
||||||
)
|
)
|
||||||
@formEnable( @el.find('.form-password') )
|
@formEnable( @el.find('.form-password') )
|
||||||
|
|
||||||
App.Config.set( 'password_reset', Index, 'Routes' )
|
App.Config.set('password_reset', Index, 'Routes')
|
||||||
|
|
||||||
class Verify extends App.ControllerContent
|
class Verify extends App.ControllerContent
|
||||||
events:
|
events:
|
||||||
|
@ -105,10 +105,10 @@ class Verify extends App.ControllerContent
|
||||||
url: @apiPath + '/users/password_reset_verify'
|
url: @apiPath + '/users/password_reset_verify'
|
||||||
data: JSON.stringify(params)
|
data: JSON.stringify(params)
|
||||||
processData: true
|
processData: true
|
||||||
success: @render_change
|
success: @renderChange
|
||||||
)
|
)
|
||||||
|
|
||||||
render_change: (data) =>
|
renderChange: (data) =>
|
||||||
if data.message is 'ok'
|
if data.message is 'ok'
|
||||||
configure_attributes = [
|
configure_attributes = [
|
||||||
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 100, null: false, class: 'input', },
|
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 100, null: false, class: 'input', },
|
||||||
|
@ -161,10 +161,10 @@ class Verify extends App.ControllerContent
|
||||||
url: @apiPath + '/users/password_reset_verify'
|
url: @apiPath + '/users/password_reset_verify'
|
||||||
data: JSON.stringify(params)
|
data: JSON.stringify(params)
|
||||||
processData: true
|
processData: true
|
||||||
success: @render_changed
|
success: @renderChanged
|
||||||
)
|
)
|
||||||
|
|
||||||
render_changed: (data, status, xhr) =>
|
renderChanged: (data, status, xhr) =>
|
||||||
if data.message is 'ok'
|
if data.message is 'ok'
|
||||||
App.Auth.login(
|
App.Auth.login(
|
||||||
data:
|
data:
|
||||||
|
|
|
@ -49,6 +49,7 @@ class Widget extends App.Controller
|
||||||
.on 'blur.translation', '.translation', (e) ->
|
.on 'blur.translation', '.translation', (e) ->
|
||||||
element = $(e.target)
|
element = $(e.target)
|
||||||
source = element.attr('title')
|
source = element.attr('title')
|
||||||
|
return if !source
|
||||||
|
|
||||||
# get new translation
|
# get new translation
|
||||||
translation_new = element.text()
|
translation_new = element.text()
|
||||||
|
@ -62,6 +63,7 @@ class Widget extends App.Controller
|
||||||
App.i18n.setMap(source, translation_new)
|
App.i18n.setMap(source, translation_new)
|
||||||
|
|
||||||
# replace rest in page
|
# replace rest in page
|
||||||
|
source = source.replace('\'', '\\\'')
|
||||||
$(".translation[title='#{source}']").text(translation_new)
|
$(".translation[title='#{source}']").text(translation_new)
|
||||||
|
|
||||||
# update permanent translation mapString
|
# update permanent translation mapString
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
class Widget extends App.Controller
|
||||||
|
constructor: ->
|
||||||
|
|
||||||
|
# for browser test
|
||||||
|
App.Event.bind('user_signup_verify', (user) ->
|
||||||
|
new Modal(user: user)
|
||||||
|
'user_signup_verify'
|
||||||
|
)
|
||||||
|
|
||||||
|
App.Event.bind('auth:login', (user) =>
|
||||||
|
return if !user
|
||||||
|
@verifyLater(user.id)
|
||||||
|
'user_signup_verify'
|
||||||
|
)
|
||||||
|
currentUserId = App.Session.get('id')
|
||||||
|
return if !currentUserId
|
||||||
|
@verifyLater(currentUserId)
|
||||||
|
|
||||||
|
verifyLater: (userId) =>
|
||||||
|
delay = =>
|
||||||
|
@verify(userId)
|
||||||
|
@delay(delay, 5000, 'user_signup_verify_dialog')
|
||||||
|
|
||||||
|
verify: (userId) ->
|
||||||
|
return if !userId
|
||||||
|
user = App.User.find(userId)
|
||||||
|
return if user.source isnt 'signup'
|
||||||
|
return if user.verified is true
|
||||||
|
currentTime = new Date().getTime()
|
||||||
|
createdAt = Date.parse(user.created_at)
|
||||||
|
diff = currentTime - createdAt
|
||||||
|
max = 1000 * 60 * 30 # show message if account is older then 30 minutes
|
||||||
|
return if diff < max
|
||||||
|
new Modal(user: user)
|
||||||
|
|
||||||
|
class Modal extends App.ControllerModal
|
||||||
|
backdrop: false
|
||||||
|
keyboard: false
|
||||||
|
head: 'Account not verified'
|
||||||
|
small: true
|
||||||
|
buttonClose: false
|
||||||
|
buttonCancel: false
|
||||||
|
buttonSubmit: 'Resend verification email'
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
|
||||||
|
content: =>
|
||||||
|
if !@sent
|
||||||
|
return App.i18n.translateContent('Your account is not verified. Please click the link in the verification email.')
|
||||||
|
content = App.i18n.translateContent('We\'ve sent an email to _%s_. Click the link in the email to verify your account.', @user.email)
|
||||||
|
content += '<br><br>'
|
||||||
|
content += App.i18n.translateContent('If you don\'t see the email, check other places it might be, like your junk, spam, social, or other folders.')
|
||||||
|
content
|
||||||
|
|
||||||
|
onSubmit: =>
|
||||||
|
@ajax(
|
||||||
|
id: 'email_verify_send'
|
||||||
|
type: 'POST'
|
||||||
|
url: @apiPath + '/users/email_verify_send'
|
||||||
|
data: JSON.stringify(email: @user.email)
|
||||||
|
processData: true
|
||||||
|
success: @success
|
||||||
|
error: @error
|
||||||
|
)
|
||||||
|
|
||||||
|
success: (data) =>
|
||||||
|
@sent = true
|
||||||
|
@update()
|
||||||
|
|
||||||
|
# if in developer mode, redirect to verify
|
||||||
|
if data.token && @Config.get('developer_mode') is true
|
||||||
|
redirect = =>
|
||||||
|
@close()
|
||||||
|
@navigate "#email_verify/#{data.token}"
|
||||||
|
App.Delay.set(redirect, 4000)
|
||||||
|
|
||||||
|
error: =>
|
||||||
|
@contentInline = App.i18n.translateContent('Unable to send verify email.')
|
||||||
|
@update()
|
||||||
|
|
||||||
|
App.Config.set('user_signup', Widget, 'Widgets')
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="fullscreenMessage">
|
<div class="fullscreenMessage">
|
||||||
<%- @Icon('diagonal-cross', 'icon-error') %>
|
<%- @Icon('diagonal-cross', 'icon-error') %>
|
||||||
<h2><% if @status isnt undefined: %><%- @T('Status Code') %>: <%= @status %>. <% end %><%= @detail %></h2>
|
<h2><% if @status isnt undefined: %><%- @T('Status Code') %>: <%= @status %>. <% end %><%- @T(@detail) %></h2>
|
||||||
</div>
|
</div>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<div class="fullscreenMessage">
|
||||||
|
<%- @Icon('checkmark') %>
|
||||||
|
<h2><%- @T(@detail) %></h2>
|
||||||
|
</div>
|
|
@ -73,6 +73,10 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
# if it's a signup, add user to customer role
|
# if it's a signup, add user to customer role
|
||||||
if !current_user
|
if !current_user
|
||||||
|
if !params[:signup]
|
||||||
|
render json: { error_human: 'Only signup is possible!' }, status: :unprocessable_entity
|
||||||
|
return
|
||||||
|
end
|
||||||
user.updated_by_id = 1
|
user.updated_by_id = 1
|
||||||
user.created_by_id = 1
|
user.created_by_id = 1
|
||||||
|
|
||||||
|
@ -100,6 +104,9 @@ class UsersController < ApplicationController
|
||||||
user.role_ids = role_ids
|
user.role_ids = role_ids
|
||||||
user.group_ids = group_ids
|
user.group_ids = group_ids
|
||||||
|
|
||||||
|
# remember source (in case show email verify banner)
|
||||||
|
user.source = 'signup'
|
||||||
|
|
||||||
# else do assignment as defined
|
# else do assignment as defined
|
||||||
else
|
else
|
||||||
|
|
||||||
|
@ -150,14 +157,11 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
# send email verify
|
# send email verify
|
||||||
if params[:signup] && !current_user
|
if params[:signup] && !current_user
|
||||||
token = Token.create(action: 'EmailVerify', user_id: user.id)
|
result = User.signup_new_token(user)
|
||||||
NotificationFactory::Mailer.notification(
|
NotificationFactory::Mailer.notification(
|
||||||
template: 'signup',
|
template: 'signup',
|
||||||
user: user,
|
user: user,
|
||||||
objects: {
|
objects: result
|
||||||
token: token,
|
|
||||||
user: user,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
user_new = User.find(user.id).attributes_with_associations
|
user_new = User.find(user.id).attributes_with_associations
|
||||||
|
@ -393,6 +397,106 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
Resource:
|
||||||
|
POST /api/v1/users/email_verify
|
||||||
|
|
||||||
|
Payload:
|
||||||
|
{
|
||||||
|
"token": "SoMeToKeN",
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
:message => 'ok'
|
||||||
|
}
|
||||||
|
|
||||||
|
Test:
|
||||||
|
curl http://localhost/api/v1/users/email_verify.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X POST -d '{"token": "SoMeToKeN"}'
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def email_verify
|
||||||
|
if !params[:token]
|
||||||
|
render json: { message: 'No token!' }, status: :unprocessable_entity
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
user = User.signup_verify_via_token(params[:token], current_user)
|
||||||
|
if !user
|
||||||
|
render json: { message: 'Invalid token!' }, status: :unprocessable_entity
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
render json: { message: 'ok', user_email: user.email }, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
Resource:
|
||||||
|
POST /api/v1/users/email_verify_send
|
||||||
|
|
||||||
|
Payload:
|
||||||
|
{
|
||||||
|
"email": "some_email@example.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
:message => 'ok'
|
||||||
|
}
|
||||||
|
|
||||||
|
Test:
|
||||||
|
curl http://localhost/api/v1/users/email_verify_send.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X POST -d '{"email": "some_email@example.com"}'
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def email_verify_send
|
||||||
|
|
||||||
|
if !params[:email]
|
||||||
|
render json: { message: 'No email!' }, status: :unprocessable_entity
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# check is verify is possible to send
|
||||||
|
user = User.find_by(email: params[:email].downcase)
|
||||||
|
if !user
|
||||||
|
render json: { error_human: 'No such user!' }, status: :unprocessable_entity
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
#if user.verified == true
|
||||||
|
# render json: { error_human: 'Already verified!' }, status: :unprocessable_entity
|
||||||
|
# return
|
||||||
|
#end
|
||||||
|
|
||||||
|
token = Token.create(action: 'Signup', user_id: user.id)
|
||||||
|
|
||||||
|
result = User.signup_new_token(user)
|
||||||
|
if result && result[:token]
|
||||||
|
user = result[:user]
|
||||||
|
NotificationFactory::Mailer.notification(
|
||||||
|
template: 'signup',
|
||||||
|
user: user,
|
||||||
|
objects: result
|
||||||
|
)
|
||||||
|
|
||||||
|
# only if system is in develop mode, send token back to browser for browser tests
|
||||||
|
if Setting.get('developer_mode') == true
|
||||||
|
render json: { message: 'ok', token: result[:token].name }, status: :ok
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# token sent to user, send ok to browser
|
||||||
|
render json: { message: 'ok' }, status: :ok
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# unable to generate token
|
||||||
|
render json: { message: 'failed' }, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
Resource:
|
Resource:
|
||||||
POST /api/v1/users/password_reset
|
POST /api/v1/users/password_reset
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ class Token < ActiveRecord::Base
|
||||||
|
|
||||||
create new token
|
create new token
|
||||||
|
|
||||||
token = Token.create( action: 'PasswordReset', user_id: user.id )
|
token = Token.create(action: 'PasswordReset', user_id: user.id)
|
||||||
|
|
||||||
returns
|
returns
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ returns
|
||||||
|
|
||||||
check token
|
check token
|
||||||
|
|
||||||
user = Token.check( action: 'PasswordReset', name: 'TheTokenItSelf' )
|
user = Token.check(action: 'PasswordReset', name: 'TheTokenItSelf')
|
||||||
|
|
||||||
returns
|
returns
|
||||||
|
|
||||||
|
@ -42,10 +42,10 @@ returns
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.check( data )
|
def self.check(data)
|
||||||
|
|
||||||
# fetch token
|
# fetch token
|
||||||
token = Token.find_by( action: data[:action], name: data[:name] )
|
token = Token.find_by(action: data[:action], name: data[:name])
|
||||||
return if !token
|
return if !token
|
||||||
|
|
||||||
# check if token is still valid
|
# check if token is still valid
|
||||||
|
@ -81,8 +81,7 @@ cleanup old token
|
||||||
|
|
||||||
loop do
|
loop do
|
||||||
self.name = SecureRandom.hex(30)
|
self.name = SecureRandom.hex(30)
|
||||||
|
break if !Token.exists?(name: name)
|
||||||
break if !Token.exists?( name: name )
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -375,7 +375,7 @@ returns
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
reset reset password with token and set new password
|
reset password with token and set new password
|
||||||
|
|
||||||
result = User.password_reset_via_token(token,password)
|
result = User.password_reset_via_token(token,password)
|
||||||
|
|
||||||
|
@ -423,6 +423,63 @@ returns
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
|
generate new token for signup
|
||||||
|
|
||||||
|
result = User.signup_new_token(user) # or email
|
||||||
|
|
||||||
|
returns
|
||||||
|
|
||||||
|
result = {
|
||||||
|
token: token,
|
||||||
|
user: user,
|
||||||
|
}
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def self.signup_new_token(user)
|
||||||
|
return if !user
|
||||||
|
return if !user.email
|
||||||
|
|
||||||
|
# generate token
|
||||||
|
token = Token.create(action: 'Signup', user_id: user.id)
|
||||||
|
|
||||||
|
{
|
||||||
|
token: token,
|
||||||
|
user: user,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
verify signup with token
|
||||||
|
|
||||||
|
result = User.signup_verify_via_token(token, user)
|
||||||
|
|
||||||
|
returns
|
||||||
|
|
||||||
|
result = user_model # user_model if token was verified
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def self.signup_verify_via_token(token, user = nil)
|
||||||
|
|
||||||
|
# check token
|
||||||
|
local_user = Token.check(action: 'Signup', name: token)
|
||||||
|
return if !local_user
|
||||||
|
|
||||||
|
# if requested user is different to current user
|
||||||
|
return if user && local_user.id != user.id
|
||||||
|
|
||||||
|
# set verified
|
||||||
|
local_user.update_attributes(verified: true)
|
||||||
|
|
||||||
|
# delete token
|
||||||
|
Token.find_by(action: 'Signup', name: token).destroy
|
||||||
|
local_user
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
merge two users to one
|
merge two users to one
|
||||||
|
|
||||||
user = User.find(123)
|
user = User.find(123)
|
||||||
|
|
|
@ -22,4 +22,7 @@ Zammad::Application.routes.draw do
|
||||||
match api_path + '/users/:id', to: 'users#update', via: :put
|
match api_path + '/users/:id', to: 'users#update', via: :put
|
||||||
match api_path + '/users/image/:hash', to: 'users#image', via: :get
|
match api_path + '/users/image/:hash', to: 'users#image', via: :get
|
||||||
|
|
||||||
|
match api_path + '/users/email_verify', to: 'users#email_verify', via: :post
|
||||||
|
match api_path + '/users/email_verify_send', to: 'users#email_verify_send', via: :post
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,11 +3,11 @@ require 'browser_test_helper'
|
||||||
|
|
||||||
class SignupPasswordChangeAndResetTest < TestCase
|
class SignupPasswordChangeAndResetTest < TestCase
|
||||||
def test_signup
|
def test_signup
|
||||||
signup_user_email = 'signup-test-' + rand(999_999).to_s + '@example.com'
|
signup_user_email = "signup-test-#{rand(999_999)}@example.com"
|
||||||
@browser = browser_instance
|
@browser = browser_instance
|
||||||
location( url: browser_url )
|
location(url: browser_url)
|
||||||
click( css: 'a[href="#signup"]' )
|
click(css: 'a[href="#signup"]')
|
||||||
exists( css: '.signup' )
|
exists(css: '.signup')
|
||||||
|
|
||||||
# signup
|
# signup
|
||||||
set(
|
set(
|
||||||
|
@ -30,10 +30,10 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
css: 'input[name="password_confirm"]',
|
css: 'input[name="password_confirm"]',
|
||||||
value: 'some-pass',
|
value: 'some-pass',
|
||||||
)
|
)
|
||||||
click( css: 'button.js-submit' )
|
click(css: 'button.js-submit')
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
exists_not( css: '.signup' )
|
exists_not(css: '.signup')
|
||||||
|
|
||||||
match(
|
match(
|
||||||
css: '.user-menu .user a',
|
css: '.user-menu .user a',
|
||||||
|
@ -41,11 +41,56 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
attribute: 'title',
|
attribute: 'title',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# check email verify
|
||||||
|
location(url: "#{browser_url}#email_verify/not_existing")
|
||||||
|
watch_for(
|
||||||
|
css: '#content',
|
||||||
|
value: 'Unable to verify email',
|
||||||
|
)
|
||||||
|
logout()
|
||||||
|
|
||||||
|
login(
|
||||||
|
username: signup_user_email,
|
||||||
|
password: 'some-pass',
|
||||||
|
url: "#{browser_url}#email_verify/not_existing2",
|
||||||
|
)
|
||||||
|
watch_for(
|
||||||
|
css: '#content',
|
||||||
|
value: 'Unable to verify email',
|
||||||
|
)
|
||||||
|
execute(
|
||||||
|
js: 'App.Event.trigger("user_signup_verify", App.Session.get())',
|
||||||
|
)
|
||||||
|
watch_for(
|
||||||
|
css: '.modal',
|
||||||
|
value: 'Account not verified',
|
||||||
|
)
|
||||||
|
click(css: '.modal .js-submit')
|
||||||
|
execute(
|
||||||
|
js: 'App.Auth.logout()',
|
||||||
|
)
|
||||||
|
sleep 6
|
||||||
|
watch_for(
|
||||||
|
css: '#login',
|
||||||
|
)
|
||||||
|
login(
|
||||||
|
username: signup_user_email,
|
||||||
|
password: 'some-pass',
|
||||||
|
)
|
||||||
|
watch_for(
|
||||||
|
css: '#content',
|
||||||
|
value: 'Your email is verified',
|
||||||
|
)
|
||||||
|
exists_not(
|
||||||
|
css: '.modal',
|
||||||
|
)
|
||||||
|
sleep 2
|
||||||
|
|
||||||
# change password
|
# change password
|
||||||
click( css: '.navbar-items-personal .user a' )
|
click(css: '.navbar-items-personal .user a')
|
||||||
sleep 1
|
sleep 1
|
||||||
click( css: 'a[href="#profile"]' )
|
click(css: 'a[href="#profile"]')
|
||||||
click( css: 'a[href="#profile/password"]' )
|
click(css: 'a[href="#profile/password"]')
|
||||||
set(
|
set(
|
||||||
css: 'input[name="password_old"]',
|
css: 'input[name="password_old"]',
|
||||||
value: 'nonexisiting',
|
value: 'nonexisiting',
|
||||||
|
@ -58,7 +103,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
css: 'input[name="password_new_confirm"]',
|
css: 'input[name="password_new_confirm"]',
|
||||||
value: 'some',
|
value: 'some',
|
||||||
)
|
)
|
||||||
click( css: '.content .btn--primary' )
|
click(css: '.content .btn--primary')
|
||||||
|
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
|
@ -73,7 +118,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
css: 'input[name="password_new_confirm"]',
|
css: 'input[name="password_new_confirm"]',
|
||||||
value: 'some2',
|
value: 'some2',
|
||||||
)
|
)
|
||||||
click( css: '.content .btn--primary' )
|
click(css: '.content .btn--primary')
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
value: 'passwords do not match',
|
value: 'passwords do not match',
|
||||||
|
@ -87,7 +132,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
css: 'input[name="password_new_confirm"]',
|
css: 'input[name="password_new_confirm"]',
|
||||||
value: 'some',
|
value: 'some',
|
||||||
)
|
)
|
||||||
click( css: '.content .btn--primary' )
|
click(css: '.content .btn--primary')
|
||||||
|
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
|
@ -102,7 +147,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
css: 'input[name="password_new_confirm"]',
|
css: 'input[name="password_new_confirm"]',
|
||||||
value: 'some-pass-new',
|
value: 'some-pass-new',
|
||||||
)
|
)
|
||||||
click( css: '.content .btn--primary' )
|
click(css: '.content .btn--primary')
|
||||||
|
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
|
@ -117,7 +162,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
css: 'input[name="password_new_confirm"]',
|
css: 'input[name="password_new_confirm"]',
|
||||||
value: 'some-pass-new2',
|
value: 'some-pass-new2',
|
||||||
)
|
)
|
||||||
click( css: '.content .btn--primary' )
|
click(css: '.content .btn--primary')
|
||||||
|
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
|
@ -133,7 +178,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
logout()
|
logout()
|
||||||
|
|
||||||
# reset password (not possible)
|
# reset password (not possible)
|
||||||
location( url: browser_url + '/#password_reset_verify/not_existing_token' )
|
location(url: browser_url + '/#password_reset_verify/not_existing_token')
|
||||||
|
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
|
@ -147,7 +192,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
url: browser_url,
|
url: browser_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
location( url: browser_url + '/#password_reset' )
|
location(url: browser_url + '/#password_reset')
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
match_not(
|
match_not(
|
||||||
|
@ -157,13 +202,13 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
logout()
|
logout()
|
||||||
|
|
||||||
# reset password (correct way)
|
# reset password (correct way)
|
||||||
click( css: 'a[href="#password_reset"]' )
|
click(css: 'a[href="#password_reset"]')
|
||||||
|
|
||||||
set(
|
set(
|
||||||
css: 'input[name="username"]',
|
css: 'input[name="username"]',
|
||||||
value: 'nonexisiting',
|
value: 'nonexisiting',
|
||||||
)
|
)
|
||||||
click( css: '.content .btn--primary' )
|
click(css: '.content .btn--primary')
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
value: 'address invalid',
|
value: 'address invalid',
|
||||||
|
@ -173,7 +218,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
css: 'input[name="username"]',
|
css: 'input[name="username"]',
|
||||||
value: signup_user_email,
|
value: signup_user_email,
|
||||||
)
|
)
|
||||||
click( css: '.content .btn--primary' )
|
click(css: '.content .btn--primary')
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
value: 'sent password reset instructions',
|
value: 'sent password reset instructions',
|
||||||
|
@ -194,7 +239,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
css: 'input[name="password_confirm"]',
|
css: 'input[name="password_confirm"]',
|
||||||
value: 'some2',
|
value: 'some2',
|
||||||
)
|
)
|
||||||
click( css: '.content .btn--primary' )
|
click(css: '.content .btn--primary')
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
value: 'passwords do not match',
|
value: 'passwords do not match',
|
||||||
|
@ -208,7 +253,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
css: 'input[name="password_confirm"]',
|
css: 'input[name="password_confirm"]',
|
||||||
value: 'some',
|
value: 'some',
|
||||||
)
|
)
|
||||||
click( css: '.content .btn--primary' )
|
click(css: '.content .btn--primary')
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
value: 'it must be at least',
|
value: 'it must be at least',
|
||||||
|
@ -222,7 +267,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
css: 'input[name="password_confirm"]',
|
css: 'input[name="password_confirm"]',
|
||||||
value: 'some-pass-new',
|
value: 'some-pass-new',
|
||||||
)
|
)
|
||||||
click( css: '.content .btn--primary' )
|
click(css: '.content .btn--primary')
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
value: 'must contain at least 1 digit',
|
value: 'must contain at least 1 digit',
|
||||||
|
@ -236,7 +281,7 @@ class SignupPasswordChangeAndResetTest < TestCase
|
||||||
css: 'input[name="password_confirm"]',
|
css: 'input[name="password_confirm"]',
|
||||||
value: 'some-pass-new2',
|
value: 'some-pass-new2',
|
||||||
)
|
)
|
||||||
click( css: '.content .btn--primary' )
|
click(css: '.content .btn--primary')
|
||||||
watch_for(
|
watch_for(
|
||||||
css: 'body',
|
css: 'body',
|
||||||
value: 'Your password has been changed',
|
value: 'Your password has been changed',
|
||||||
|
|
Loading…
Reference in a new issue