-
-
Save sadovnychyi/2329328 to your computer and use it in GitHub Desktop.
webapp2: Password reset
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import models | |
from wtforms import Form | |
from wtforms import fields | |
from wtforms import validators | |
class PasswordRestForm(Form): | |
email = fields.TextField('email') | |
class PasswordChangeForm(Form): | |
current = fields.PasswordField('Current Password') | |
password = fields.PasswordField('New Password',) | |
confirm = fields.PasswordField('New Password again', [validators.EqualTo('password', 'Passwords must match.')]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BaseHandler(webapp2.RequestHandler): | |
""" | |
BaseHandler for all requests | |
Holds the auth and session properties so they are reachable for all requests | |
""" | |
def dispatch(self): | |
# Get a session store for this request. | |
self.session_store = sessions.get_store(request=self.request) | |
try: | |
# Dispatch the request. | |
webapp2.RequestHandler.dispatch(self) | |
finally: | |
# Save all sessions. | |
self.session_store.save_sessions(self.response) | |
@webapp2.cached_property | |
def auth(self): | |
return auth.get_auth() | |
@webapp2.cached_property | |
def session(self): | |
# Returns a session using the default cookie key. | |
return self.session_store.get_session() | |
@webapp2.cached_property | |
def messages(self): | |
return self.session.get_flashes(key='_messages') | |
def add_message(self, message, level=None): | |
self.session.add_flash(message, level, key='_messages') | |
@webapp2.cached_property | |
def auth_config(self): | |
""" | |
Dict to hold urls for login/logout | |
""" | |
return { | |
'login_url': self.uri_for('user-login'), | |
'logout_url': self.uri_for('user-logout') | |
} | |
@webapp2.cached_property | |
def user(self): | |
return self.auth.get_user_by_session() | |
@webapp2.cached_property | |
def user_id(self): | |
return str(self.user['user_id']) if self.user else None | |
@webapp2.cached_property | |
def jinja2(self): | |
return jinja2.get_jinja2(app=self.app) | |
def render_response(self, filename, **kwargs): | |
kwargs.update({ | |
'current_user': self.user, | |
'current_url': self.request.url, | |
}) | |
kwargs.update(self.auth_config) | |
if self.messages: | |
kwargs['messages'] = self.messages | |
self.response.write(self.jinja2.render_template(filename, **kwargs)) | |
class AccountPasswordHandler(BaseHandler): | |
@user_required | |
def get(self, **kwargs): | |
context = { | |
'form': self.form, | |
'user': self.user, | |
'template': 'accounts/password_change.html', | |
} | |
self.render_response('base.html', **context) | |
@user_required | |
def post(self, **kwargs): | |
if self.form.validate(): | |
# test current password | |
user = User.get_by_id(int(self.user_id)) | |
if not security.check_password_hash(self.form.current.data, user.password): | |
self.add_message('Your current Password did not match our records', 'error') | |
return self.get(**kwargs) | |
# change password | |
user.password = security.generate_password_hash(self.form.password.data, length=12) | |
user.put() | |
self.add_message('Password changed successfully', 'success') | |
return self.redirect(self.url_for('account-index')) | |
self.add_message('Password changed failed.', 'error') | |
return self.get(**kwargs) | |
@webapp2.cached_property | |
def form(self): | |
return forms.PasswordChangeForm(self.request.POST) | |
class EmailPasswordResetHandler(BaseHandler): | |
def post(self): | |
recipient = User.get_by_id(int(self.request.get('recipient_id'))) | |
token = User.token_model.create(recipient.key.id(), 'password_reset').token | |
subject = "SiteName: Password Assistance" | |
template = '/emails/password_reset.html' | |
reset_url = self.uri_for('password-reset-check', token=token, _full=True) | |
email = mail.EmailMessage() | |
email.sender = FROM_EMAIL | |
email.subject = subject | |
email.to = '%s <%s>' % (recipient.displayName, recipient.email) | |
context = { | |
'recipient': recipient, | |
'reset_url': reset_url, | |
} | |
email.body = self.jinja2.render_template(template, **context) | |
email.send() | |
class PasswordResetHandler(BaseHandler): | |
def get(self): | |
if self.user: | |
self.redirect_to('profile-show', id=self.user_id) | |
context = { | |
'template': 'accounts/password_reset.html', | |
} | |
return self.render_response('base.html', **context) | |
def post(self): | |
email = self.request.POST.get('email') | |
auth_id = "own:%s" % email | |
user = User.get_by_auth_id(auth_id) | |
if user is not None: | |
# Send Message Received Email | |
taskqueue.add(url='/emails/password/reset', params={ | |
'recipient_id': user.key.id(), | |
}) | |
self.add_message('Password reset instruction have been sent to %s. Please check your inbox.' % email, 'success') | |
return self.redirect_to('user-login') | |
self.add_message('Your email address was not found. Please try another or <a href="/register">create an account</a>.', 'error') | |
return self.redirect_to('password-reset') | |
class PasswordResetCompleteHandler(BaseHandler): | |
def get(self, token): | |
# Verify token | |
token = User.token_model.query(User.token_model.token == token).get() | |
if token is None: | |
self.add_message('The token could not be found, please resubmit your email.', 'error') | |
self.redirect_to('password-reset') | |
context = { | |
'form': self.form, | |
'template': 'accounts/password_reset_complete.html', | |
} | |
return self.render_response('base.html', **context) | |
def post(self, token): | |
if self.form.validate(): | |
token = User.token_model.query(User.token_model.token == token).get() | |
# test current password | |
user = User.get_by_id(int(token.user)) | |
if token and user: | |
user.password = security.generate_password_hash(self.form.password.data, length=12) | |
user.put() | |
# Delete token | |
token.key.delete() | |
# Login User | |
self.auth.get_user_by_password(user.auth_ids[0], self.form.password.data) | |
self.add_message('Password changed successfully', 'success') | |
return self.redirect_to('profile-show', id=user.key.id()) | |
self.add_message('Please correct the form errors.', 'error') | |
return self.get(token) | |
@webapp2.cached_property | |
def form(self): | |
return forms.PasswordChangeForm(self.request.POST) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
routes = [ | |
# Password | |
Route('/password/reset', handler='handlers.PasswordResetHandler', name='password-reset'), | |
Route('/password/reset/<token>', handler='handlers.PasswordResetCompleteHandler', name='password-reset-check'), | |
] | |
application = webapp2.WSGIApplication(routes, debug=DEBUG, config=config) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment