Skip to content

Instantly share code, notes, and snippets.

@kylefinley
Created January 3, 2012 16:16
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save kylefinley/1555570 to your computer and use it in GitHub Desktop.
Save kylefinley/1555570 to your computer and use it in GitHub Desktop.
webapp2: Password reset
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.')])
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)
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)
@coto
Copy link

coto commented Jan 28, 2012

how did you import wtforms on app engine? For me it is an unresolved reference.

@kylefinley
Copy link
Author

You have to add the wtforms package to your application. Here's the link to the source: https://bitbucket.org/simplecodes/wtforms/

@coto
Copy link

coto commented Jan 28, 2012

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment