# -*- coding: utf-8 -*- # vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 ############################################################################### # ScribeEngine - Open Source Blog Software # # --------------------------------------------------------------------------- # # Copyright (c) 2010 Raoul Snyman # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # # Software Foundation; version 2 of the License. # # # # This program is distributed in the hope that it will be useful, but WITHOUT # # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # # more details. # # # # You should have received a copy of the GNU General Public License along # # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### import logging import string import random from urlparse import urlsplit from datetime import datetime from formencode.validators import Int from pytz import all_timezones from scribeengine.lib.base import * from scribeengine.lib.validation.client import JSString, JSEmail from scribeengine.lib.validation.server import UnicodeString, Email, FieldsMatch from scribeengine.lib import utils from scribeengine.model import User from scribeengine.model.meta import Session log = logging.getLogger(__name__) class AccountController(BaseController): @authenticate() def index(self): c.page_title = u'My Account' c.timezones = all_timezones return render(u'/account/index.mako') @jsvalidate(u'account-account') def index_jsschema(self): return { u'account-nick': JSString(required=True, message=u'You need to type in a nick.'), u'account-email': JSEmail(required=True, message=u'You need to supply a valid e-mail address.') } def register(self): c.page_title = u'Register' return render(u'/account/register.mako') @jsvalidate(u'account-register') def register_jsschema(self): return { u'register-email': JSEmail(required=True, message=u'You haven\'t typed in an e-mail address.'), u'register-password': JSString(required=True, message=u'You haven\'t typed in a password.'), u'register-confirm': JSString(required=True, equalTo=u'#password', message=u'Your passwords don\'t match.') } def register_schema(self): return { 'register-email': Email(not_empty=True, messages={'empty': u'You haven\'t typed in an e-mail address.'}), 'register-password': UnicodeString(not_empty=True, messages={'empty': u'You haven\'t typed in a password.'}), 'confirm-password': [ FieldsMatch('register-password', 'register-confirm', messages={'invalid': u'Your passwords don\'t match.'})] } def register_POST(self): activation_code = u''.join(random.sample(string.letters + string.digits, 40)) user = User( nick=c.form_values[u'register-nick'], email=c.form_values[u'register-email'], password=utils.hash_password(c.form_values[u'register-password']), activation_key=activation_code ) Session.add(user) Session.commit() blog_mail = Session.query(Variable).get(u'blog mail') blog_title = Session.query(Variable).get(u'blog title') blog_host = Session.query(Variable).get(u'blog host') if not blog_host: url = u'%s://%s' % (request.environ[u'wsgi.url_scheme'], request.environ[u'HTTP_HOST']) blog_host = Variable(key=u'blog host', value=url) Session.add(blog_host) Session.commit() utils.send_mail(u'/email/activate.mako', u'%s <%s>' % (user.nick, user.email), u'%s <%s>' % (blog_mail.value, blog_title.value), u'[%s] Activate your account!' % blog_title.value, { 'user': user, 'blog_title': blog_title.value, 'blog_host': blog_host.value }) h.flash.set_message(u'An e-mail has been sent to your e-mail address. ' u'Please activate your account by clicking on the link in your ' u'e-mail.', u'success') h.redirect_to('/') def activate(self, id=None): activation_code = request.GET.get('code') if not activation_code: h.flash.set_message(u'Your activation code was missing or ' u'incorrect. Please check your activation e-mail.', u'error') h.redirect_to(h.url_for(controller=u'account', action=u'register')) if not id: h.flash.set_message(u'Your username was missing or incorrect. ' u'Please check your activation e-mail.', u'error') h.redirect_to(h.url_for(controller=u'account', action=u'register')) user = Session.query(User)\ .filter_by(id=id)\ .filter_by(activation_key=activation_code)\ .first() if not user: h.flash.set_message(u'Your username or activation code is ' u'incorrect. Please check your activation e-mail.', u'error') h.redirect_to(h.url_for(action=u'register')) user.activation_key = None user.modified = datetime.now() Session.add(user) Session.commit() h.flash.set_message(u'Your account has been activated! Please log in ' u'with your e-mail address and the password you typed in during ' u'registration.', u'success') h.redirect_to(h.url_for(controller=u'account', action=u'login')) def reset(self): c.page_title = u'Reset Password' return render(u'/account/reset.mako') @jsvalidate(u'account-reset') def reset_jsschema(self): return { u'reset-email': JSEmail(required=True, message=u'You haven\'t typed in a valid e-mail address.') } def reset_schema(self): return { 'reset-email': Email(not_empty=True, messages={'empty': u'You haven\'t typed in a valid e-mail address.'}) } def reset_POST(self): email = c.form_values[u'reset-email'] user = Session.query(User).filter_by(email=email).first() if not user: h.flash.set_message(u'Your e-mail address is not in the system.', u'error') else: activation_code = u''.join(random.sample(string.letters + string.digits, 40)) user.activation_key = activation_code user.modified = datetime.now() Session.add(user) Session.commit() blog_mail = Session.query(Variable).get(u'blog mail') blog_title = Session.query(Variable).get(u'blog title') blog_host = Session.query(Variable).get(u'blog host') if not blog_host: url = u'%s://%s' % (request.environ[u'wsgi.url_scheme'], request.environ[u'HTTP_HOST']) blog_host = Variable(key=u'blog host', value=url) Session.add(blog_host) Session.commit() utils.send_mail(u'/email/reset.mako', u'%s <%s>' % (user.nick, user.email), u'%s <%s>' % (blog_mail.value, blog_title.value), u'[%s] Reset your password!' % blog_title.value, { 'user': user, 'blog_title': blog_title.value, 'blog_host': blog_host.value }) h.flash.set_message(u'An e-mail has been sent to your e-mail address. ' u'Please reset your password by clicking on the link in your ' u'e-mail.', u'success') h.redirect_to('/account/login') def password(self, id=None): if not id or not request.GET.get(u'code'): h.flash.set_message(u'There was a problem with your activation code, please reset your password again.', u'error') h.redirect_to(h.url_for(controller=u'account', action=u'login')) c.user = Session.query(User).get(id) if not c.user: h.flash.set_message(u'There was a problem with your account, please reset your password again.', u'error') h.redirect_to(h.url_for(controller=u'account', action=u'login')) if c.user.activation_key != request.GET.get(u'code'): h.flash.set_message(u'There was a problem with your activation code, please reset your password again.', u'error') h.redirect_to(h.url_for(controller=u'account', action=u'login')) c.page_title = u'Change Password' return render(u'/account/password.mako') @jsvalidate(u'account-password') def password_jsschema(self): return { u'password-password': JSString(required=True, message=u'You haven\'t typed in a password.'), u'password-confirm': JSString(required=True, equalTo=u'#password-password', message=u'Your passwords don\'t match.') } def password_schema(self): return { 'password-password': UnicodeString(not_empty=True, messages={'empty': u'You haven\'t typed in a password.'}), 'confirm-password': [FieldsMatch('password-password', 'password-confirm', messages={'invalid': u'Your passwords don\'t match.'})] } def password_POST(self, id=None): user = Session.query(User).get(id) if not user: h.flash.set_message(u'There was a problem with your account, please reset your password again.', u'error') h.redirect_to(h.url_for(controller=u'account', action=u'login')) user.password = utils.hash_password(c.form_values[u'password-password']) user.activation_key = None user.modified = datetime.now() Session.add(user) Session.commit() h.flash.set_message(u'Successfully updated your password. Please login with your new password.', u'success') h.redirect_to('/account/login') def login(self): if u'redirect_url' not in session and u'REFERER' in request.headers: session[u'redirect_url'] = str(urlsplit(request.headers[u'REFERER']).path) session.save() c.page_title = u'Login' return render(u'/account/login.mako') @jsvalidate(u'account-login') def login_jsschema(self): return { u'login-email': JSEmail(required=True, message=u'You haven\'t typed in an e-mail address.'), u'login-password': JSString(required=True, message=u'You haven\'t typed in a password.') } def login_schema(self): return { 'login-email': Email(not_empty=True, messages={'empty': u'You haven\'t typed in an e-mail address.'}), 'login-password': UnicodeString(not_empty=True, messages={'empty': u'You haven\'t typed in a password.'}) } def login_POST(self): log.debug('Logging in as "%s" with password "%s"', c.form_values[u'login-email'], c.form_values[u'login-password']) user = Session.query(User).filter_by(email=c.form_values[u'login-email']).first() password = utils.hash_password(c.form_values[u'login-password']) if not user or user.password != password: log.debug('Username or password are incorrect.') h.flash.set_message(u'Your username or password are incorrect.', u'error') h.redirect_to(h.url_for(controller=u'account', action=u'login')) elif user and user.activation_key is not None: log.debug('Unactivated account.') h.flash.set_message(u'Your account has not yet been activated. Please check your e-mail for a link to activate your account.', u'error') h.redirect_to(h.url_for(controller=u'account', action=u'login')) elif user and user.password == password: log.debug('Logged in successfully.') redirect_url = str(session.get(u'redirect_url', u'/')) if u'redirect_url' in session: del session[u'redirect_url'] else: redirect_url = '/' if redirect_url == '/account/login': redirect_url = '/' session[u'REMOTE_USER'] = user.id session.save() h.flash.set_message(u'You have logged in successfully.', u'success') h.redirect_to(redirect_url) else: log.debug('"user" is None.') del session[u'REMOTE_USER'] session.save() h.flash.set_message(u'There was a problem logging you in.', u'error') h.redirect_to(h.url_for(controller=u'account', action=u'login')) def logout(self): del session[u'REMOTE_USER'] session.save() h.flash.set_message(u'You have logged out successfully.', u'success') h.redirect_to('/')