2010-01-15 20:55:30 +00:00
|
|
|
# -*- 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
|
2010-02-24 11:40:39 +00:00
|
|
|
from urlparse import urlsplit
|
2010-01-30 21:39:44 +00:00
|
|
|
from datetime import datetime
|
2010-01-15 20:55:30 +00:00
|
|
|
|
2010-02-16 20:10:09 +00:00
|
|
|
from formencode.validators import Int
|
2010-03-02 14:00:05 +00:00
|
|
|
from pytz import all_timezones
|
2010-02-16 20:10:09 +00:00
|
|
|
|
2010-01-15 20:55:30 +00:00
|
|
|
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__)
|
|
|
|
|
2010-02-06 21:41:16 +00:00
|
|
|
class AccountController(BaseController):
|
2010-01-15 20:55:30 +00:00
|
|
|
|
2010-03-02 13:21:43 +00:00
|
|
|
@authenticate()
|
2010-01-15 20:55:30 +00:00
|
|
|
def index(self):
|
2010-03-02 13:21:43 +00:00
|
|
|
c.page_title = u'My Account'
|
2010-03-02 14:00:05 +00:00
|
|
|
c.timezones = all_timezones
|
2010-03-02 13:21:43 +00:00
|
|
|
return render(u'/account/index.mako')
|
2010-01-15 20:55:30 +00:00
|
|
|
|
2010-03-08 12:50:18 +00:00
|
|
|
@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.')
|
|
|
|
}
|
|
|
|
|
2010-03-09 12:18:43 +00:00
|
|
|
def index_schema(self):
|
|
|
|
return {
|
|
|
|
'account-nick': UnicodeString(not_empty=True,
|
|
|
|
messages={u'empty': u'You need to type in a nick.'}),
|
|
|
|
'account-email': Email(not_empty=True,
|
|
|
|
messages={u'empty': u'You need to supply a valid e-mail address.'})
|
|
|
|
}
|
|
|
|
|
|
|
|
def index_POST(self):
|
|
|
|
try:
|
|
|
|
for key, value in c.form_values.iteritems():
|
|
|
|
setattr(c.current_user, key[8:], value)
|
|
|
|
Session.add(c.current_user)
|
|
|
|
Session.commit()
|
|
|
|
h.flash.set_message(u'Successfully updated your account.', u'success')
|
|
|
|
except:
|
|
|
|
h.flash.set_message(u'There was a problem updating your account.', u'error')
|
|
|
|
h.redirect_to(h.url_for(controller=u'account'))
|
|
|
|
|
2010-03-26 12:33:41 +00:00
|
|
|
@authenticate()
|
|
|
|
def password(self):
|
|
|
|
c.page_title = u'Your 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.'})]
|
|
|
|
}
|
|
|
|
|
|
|
|
@authenticate()
|
|
|
|
def password_POST(self):
|
|
|
|
password_hash = utils.hash_password(c.form_values[u'password-password'])
|
|
|
|
log.debug('Old Hash: "%s"', c.current_user.password)
|
|
|
|
log.debug('New Hash: "%s"', password_hash)
|
|
|
|
c.current_user.password = password_hash
|
|
|
|
c.current_user.modified = datetime.now()
|
|
|
|
Session.add(c.current_user)
|
|
|
|
Session.commit()
|
|
|
|
h.flash.set_message(u'Successfully updated your password.', u'success')
|
|
|
|
h.redirect_to('/account/password')
|
|
|
|
|
2010-01-15 20:55:30 +00:00
|
|
|
def register(self):
|
|
|
|
c.page_title = u'Register'
|
2010-02-06 21:41:16 +00:00
|
|
|
return render(u'/account/register.mako')
|
2010-01-15 20:55:30 +00:00
|
|
|
|
2010-03-08 12:50:18 +00:00
|
|
|
@jsvalidate(u'account-register')
|
2010-01-15 20:55:30 +00:00
|
|
|
def register_jsschema(self):
|
|
|
|
return {
|
2010-03-08 12:50:18 +00:00
|
|
|
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.')
|
2010-01-15 20:55:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def register_schema(self):
|
|
|
|
return {
|
2010-03-08 12:50:18 +00:00
|
|
|
'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.'})]
|
2010-01-15 20:55:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def register_POST(self):
|
|
|
|
activation_code = u''.join(random.sample(string.letters + string.digits, 40))
|
|
|
|
user = User(
|
2010-02-14 21:26:06 +00:00
|
|
|
nick=c.form_values[u'register-nick'],
|
|
|
|
email=c.form_values[u'register-email'],
|
|
|
|
password=utils.hash_password(c.form_values[u'register-password']),
|
2010-01-15 20:55:30 +00:00
|
|
|
activation_key=activation_code
|
|
|
|
)
|
|
|
|
Session.add(user)
|
|
|
|
Session.commit()
|
2010-01-30 21:39:44 +00:00
|
|
|
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')
|
2010-01-15 20:55:30 +00:00
|
|
|
h.redirect_to('/')
|
|
|
|
|
2010-01-25 21:32:48 +00:00
|
|
|
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')
|
2010-02-06 22:03:29 +00:00
|
|
|
h.redirect_to(h.url_for(controller=u'account', action=u'register'))
|
2010-01-25 21:32:48 +00:00
|
|
|
if not id:
|
|
|
|
h.flash.set_message(u'Your username was missing or incorrect. '
|
|
|
|
u'Please check your activation e-mail.', u'error')
|
2010-02-06 22:03:29 +00:00
|
|
|
h.redirect_to(h.url_for(controller=u'account', action=u'register'))
|
2010-01-30 21:39:44 +00:00
|
|
|
user = Session.query(User)\
|
|
|
|
.filter_by(id=id)\
|
2010-01-25 21:32:48 +00:00
|
|
|
.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
|
2010-01-30 21:39:44 +00:00
|
|
|
user.modified = datetime.now()
|
2010-01-25 21:32:48 +00:00
|
|
|
Session.add(user)
|
|
|
|
Session.commit()
|
2010-01-30 21:39:44 +00:00
|
|
|
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')
|
2010-02-06 22:03:29 +00:00
|
|
|
h.redirect_to(h.url_for(controller=u'account', action=u'login'))
|
2010-01-25 21:32:48 +00:00
|
|
|
|
2010-02-11 20:09:31 +00:00
|
|
|
def reset(self):
|
|
|
|
c.page_title = u'Reset Password'
|
|
|
|
return render(u'/account/reset.mako')
|
|
|
|
|
2010-02-14 21:26:06 +00:00
|
|
|
@jsvalidate(u'account-reset')
|
2010-02-11 20:09:31 +00:00
|
|
|
def reset_jsschema(self):
|
|
|
|
return {
|
2010-02-14 21:26:06 +00:00
|
|
|
u'reset-email': JSEmail(required=True, message=u'You haven\'t typed in a valid e-mail address.')
|
2010-02-11 20:09:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def reset_schema(self):
|
|
|
|
return {
|
2010-02-14 21:26:06 +00:00
|
|
|
'reset-email': Email(not_empty=True, messages={'empty': u'You haven\'t typed in a valid e-mail address.'})
|
2010-02-11 20:09:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def reset_POST(self):
|
2010-02-14 21:26:06 +00:00
|
|
|
email = c.form_values[u'reset-email']
|
2010-02-11 20:09:31 +00:00
|
|
|
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()
|
2010-02-14 21:26:06 +00:00
|
|
|
utils.send_mail(u'/email/reset.mako', u'%s <%s>' % (user.nick, user.email),
|
2010-02-11 20:09:31 +00:00
|
|
|
u'%s <%s>' % (blog_mail.value, blog_title.value),
|
2010-02-14 21:26:06 +00:00
|
|
|
u'[%s] Reset your password!' % blog_title.value,
|
2010-02-11 20:09:31 +00:00
|
|
|
{
|
|
|
|
'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. '
|
2010-02-14 21:26:06 +00:00
|
|
|
u'Please reset your password by clicking on the link in your '
|
2010-02-11 20:09:31 +00:00
|
|
|
u'e-mail.', u'success')
|
2010-02-16 20:10:09 +00:00
|
|
|
h.redirect_to('/account/login')
|
2010-02-14 21:26:06 +00:00
|
|
|
|
2010-03-26 12:33:41 +00:00
|
|
|
def resetpassword(self, id=None):
|
|
|
|
"""
|
|
|
|
Reset your password.
|
|
|
|
"""
|
2010-02-14 21:26:06 +00:00
|
|
|
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'))
|
2010-02-16 20:10:09 +00:00
|
|
|
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'))
|
2010-03-26 12:33:41 +00:00
|
|
|
c.page_title = u'Reset Password'
|
|
|
|
return render(u'/account/resetpassword.mako')
|
2010-02-14 21:26:06 +00:00
|
|
|
|
2010-03-26 12:33:41 +00:00
|
|
|
@jsvalidate(u'account-resetpassword')
|
|
|
|
def resetpassword_jsschema(self):
|
2010-02-14 21:26:06 +00:00
|
|
|
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.')
|
|
|
|
}
|
|
|
|
|
2010-03-26 12:33:41 +00:00
|
|
|
def resetpassword_schema(self):
|
2010-02-14 21:26:06 +00:00
|
|
|
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.'})]
|
|
|
|
}
|
|
|
|
|
2010-03-26 12:33:41 +00:00
|
|
|
def resetpassword_POST(self, id=None):
|
2010-02-16 20:10:09 +00:00
|
|
|
user = Session.query(User).get(id)
|
2010-02-14 21:26:06 +00:00
|
|
|
if not user:
|
2010-03-26 12:33:41 +00:00
|
|
|
h.flash.set_message(u'There was a problem with your account, '
|
|
|
|
u'please reset your password again.', u'error')
|
2010-02-14 21:26:06 +00:00
|
|
|
h.redirect_to(h.url_for(controller=u'account', action=u'login'))
|
|
|
|
user.password = utils.hash_password(c.form_values[u'password-password'])
|
2010-02-16 20:10:09 +00:00
|
|
|
user.activation_key = None
|
2010-02-14 21:26:06 +00:00
|
|
|
user.modified = datetime.now()
|
|
|
|
Session.add(user)
|
|
|
|
Session.commit()
|
2010-03-26 12:33:41 +00:00
|
|
|
h.flash.set_message(u'Successfully updated your password. Please login '
|
|
|
|
u'with your new password.', u'success')
|
2010-02-14 21:26:06 +00:00
|
|
|
h.redirect_to('/account/login')
|
2010-02-11 20:09:31 +00:00
|
|
|
|
2010-01-15 20:55:30 +00:00
|
|
|
def login(self):
|
2010-02-24 11:40:39 +00:00
|
|
|
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()
|
2010-01-15 20:55:30 +00:00
|
|
|
c.page_title = u'Login'
|
2010-02-06 21:41:16 +00:00
|
|
|
return render(u'/account/login.mako')
|
2010-01-15 20:55:30 +00:00
|
|
|
|
2010-02-14 21:26:06 +00:00
|
|
|
@jsvalidate(u'account-login')
|
2010-01-15 20:55:30 +00:00
|
|
|
def login_jsschema(self):
|
|
|
|
return {
|
2010-02-14 21:26:06 +00:00
|
|
|
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.')
|
2010-01-15 20:55:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def login_schema(self):
|
|
|
|
return {
|
2010-02-14 21:26:06 +00:00
|
|
|
'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.'})
|
2010-01-15 20:55:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def login_POST(self):
|
2010-02-14 21:26:06 +00:00
|
|
|
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'])
|
2010-01-15 20:55:30 +00:00
|
|
|
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')
|
2010-02-06 22:03:29 +00:00
|
|
|
h.redirect_to(h.url_for(controller=u'account', action=u'login'))
|
2010-01-25 18:39:00 +00:00
|
|
|
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')
|
2010-02-06 22:03:29 +00:00
|
|
|
h.redirect_to(h.url_for(controller=u'account', action=u'login'))
|
2010-01-15 20:55:30 +00:00
|
|
|
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']
|
2010-02-24 11:40:39 +00:00
|
|
|
else:
|
|
|
|
redirect_url = '/'
|
|
|
|
if redirect_url == '/account/login':
|
|
|
|
redirect_url = '/'
|
|
|
|
session[u'REMOTE_USER'] = user.id
|
2010-01-15 20:55:30 +00:00
|
|
|
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')
|
2010-02-06 22:03:29 +00:00
|
|
|
h.redirect_to(h.url_for(controller=u'account', action=u'login'))
|
2010-01-15 20:55:30 +00:00
|
|
|
|
|
|
|
def logout(self):
|
|
|
|
del session[u'REMOTE_USER']
|
|
|
|
session.save()
|
2010-01-30 21:52:59 +00:00
|
|
|
h.flash.set_message(u'You have logged out successfully.', u'success')
|
2010-01-15 20:55:30 +00:00
|
|
|
h.redirect_to('/')
|
|
|
|
|