class PasswordResetView(object): """Password reset logic.""" def __init__(self, request): self.request = request self.session = DBSession() self.prune_expired() def prune_expired(self): """Prunes password reset requests that have expired.""" self.session.query(PasswordReset)\ .filter(PasswordReset.expires < datetime.now())\ .delete() def render_form(self): """Renders the password reset form.""" return { 'action_url': route_url('reset_password_initiate', self.request), 'title': u'Nollaa salasana', } def password_change_form(self): """Renders the form for changing a password for a valid token.""" log = logging.getLogger('nuorisovaalitadmin') reset = self.session.query(PasswordReset)\ .filter(PasswordReset.token == self.request.matchdict['token'])\ .filter(PasswordReset.expires >= datetime.now())\ .first() if reset is None: log.warn('Unknown password reset token: {token}.'.format(**self.request.matchdict)) # No matching password reset found raise NotFound user = self.session.query(User).get(reset.user_id) if user is None: log.warn('Unknown user "{0}" for password reset.'.format(reset.user_id)) raise NotFound return { 'action_url': route_url('reset_password_process', self.request), 'title': u'Vaihda salasana', 'token': reset.token, 'username': user.username, } def send_confirmation_message(self): """Sends an email confirmation message to the user.""" username = self.request.POST.get('username', '').strip() redirect_url = route_url('reset_password', self.request) log = logging.getLogger('nuorisovaalitadmin') if not username: self.request.session.flash(u'Anna käyttäjätunnus.') else: user = self.session.query(User).filter(User.username == username).first() if user is None: self.request.session.flash(u'Annettua käyttäjätunnusta ei löydy.') else: # Create a password reset request that is valid for 24 hours reset = PasswordReset(user.id, datetime.now() + timedelta(hours=24)) self.session.add(reset) message = self.create_message(user, reset) from_address = self.request.registry.settings['nuorisovaalitadmin.from_address'].strip() # TODO add sendmail to project to include it here send_mail(from_address, [user.email], message) self.request.session.flash(u'Ohjeet salasanan vaihtamiseen on lähetetty sähköpostissa.') redirect_url = self.request.application_url log.info('Sending password reset instructions to {0}.'.format(user.email)) return HTTPFound(location=redirect_url) def create_message(self, user, reset): """Returns an email.message.Message object representing the password reset message. """ from_address = self.request.registry.settings['nuorisovaalitadmin.from_address'].strip() date_format = self.request.registry.settings['nuorisovaalitadmin.date_format'].strip() subject = user.username message = Message() message['From'] = Header(from_address, 'utf-8') message['To'] = Header(u'{0} <{1}>'.format(user.username, user.email), 'utf-8') message['Subject'] = Header(subject, 'utf-8') message.set_payload(textwrap.dedent(u''' Hyvä {username}, Nuorisovaalit 2011 -ylläpitosivustolta on tehty pyyntö salasanasi uusimiseksi. Jos teit pyynnön itse, voit uusia salasanasi avaamalla seuraavan linkin selaimessa: {reset_url} Linkki vanhentuu {expiration}. Mikäli tämä viesti on mielestäsi aiheeton voit poistaa ja unohtaa sen. Salasanaasi ei ole muutettu. '''.encode('utf-8')).lstrip().format(username=user.username, expiration=reset.expires.strftime(date_format), reset_url=route_url('reset_password_token', self.request, token=reset.token))) return message def change_password(self): """Changes the password for a user.""" token = self.request.POST.get('token', '').strip() log = logging.getLogger('nuorisovaalitadmin') if token: password = self.request.POST.get('password', '') confirm_password = self.request.POST.get('confirm_password', '') if len(password.strip()) < 5: self.request.session.flash(u'Salasanan on oltava vähintään viisi merkkiä pitkä') return HTTPFound( location=route_url('reset_password_token', self.request, token=token)) elif password != confirm_password: self.request.session.flash(u'Annetut salasanat eivät vastaa toisiaan') return HTTPFound( location=route_url('reset_password_token', self.request, token=token)) else: reset = self.session.query(PasswordReset)\ .filter(PasswordReset.token == token)\ .filter(PasswordReset.expires >= datetime.now())\ .first() if reset is None: raise NotFound user = self.session.query(User).get(reset.user_id) if user is None: raise NotFound # Update the user password user.password = password self.session.add(user) self.session.delete(reset) self.request.session.flash(u'Salasana vaihdettu.') log.info('Changed password for {0}.'.format(user.username)) headers = remember(self.request, user.username) return HTTPFound(location=self.request.application_url, headers=headers) raise NotFound