@@ -294,6 +294,10 @@ def make_map(config):
rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
controller='login', action='password_reset')
rmap.connect('reset_password_confirmation',
'%s/password_reset_confirmation' % ADMIN_PREFIX,
controller='login', action='password_reset_confirmation')
#FEEDS
rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
controller='feed', action='rss',
@@ -129,8 +129,8 @@ class LoginController(BaseController):
password_reset_form = PasswordResetForm()()
try:
form_result = password_reset_form.to_python(dict(request.POST))
user_model.reset_password(form_result)
h.flash(_('Your new password was sent'),
user_model.reset_password_link(form_result)
h.flash(_('Your password reset link was sent'),
category='success')
return redirect(url('login_home'))
@@ -144,6 +144,23 @@ class LoginController(BaseController):
return render('/password_reset.html')
def password_reset_confirmation(self):
if request.GET and request.GET.get('key'):
user_model = UserModel()
user = User.get_by_api_key(request.GET.get('key'))
data = dict(email=user.email)
user_model.reset_password(data)
h.flash(_('Your password reset was successful, '
'new password has been sent to your email'),
except Exception, e:
log.error(e)
return redirect(url('reset_password'))
def logout(self):
del session['rhodecode_user']
session.save()
@@ -34,7 +34,7 @@ from time import mktime
from operator import itemgetter
from string import lower
from pylons import config
from pylons import config, url
from pylons.i18n.translation import _
from rhodecode.lib import LANGUAGES_EXTENSIONS_MAP, safe_str
@@ -249,6 +249,45 @@ def get_commits_stats(repo_name, ts_min_
log.info('LockHeld')
return 'Task with key %s already running' % lockkey
@task(ignore_result=True)
def send_password_link(user_email):
log = reset_user_password.get_logger()
except:
log = logging.getLogger(__name__)
from rhodecode.lib import auth
from rhodecode.model.db import User
sa = get_session()
user = sa.query(User).filter(User.email == user_email).scalar()
if user:
link = url('reset_password_confirmation', key=user.api_key,
qualified=True)
tmpl = """
Hello %s
We received a request to create a new password for your account.
You can generate it by clicking following URL:
%s
If you didn't request new password please ignore this email.
"""
run_task(send_email, user_email,
"RhodeCode password reset link",
tmpl % (user.short_contact, link))
log.info('send new password mail to %s', user_email)
log.error('Failed to update user password')
log.error(traceback.format_exc())
return False
return True
def reset_user_password(user_email):
@@ -280,8 +319,8 @@ def reset_user_password(user_email):
sa.rollback()
"Your new rhodecode password",
'Your new rhodecode password:%s' % (new_passwd))
"Your new RhodeCode password",
'Your new RhodeCode password:%s' % (new_passwd))
@@ -74,13 +74,19 @@ class SmtpMailer(object):
date_ = formatdate(localtime=True)
msg = MIMEMultipart()
msg.set_type('multipart/alternative')
msg.preamble = 'You will not see this in a MIME-aware mail reader.\n'
text_msg = MIMEText(body)
text_msg.set_type('text/plain')
text_msg.set_param('charset', 'UTF-8')
msg['From'] = self.mail_from
msg['To'] = ','.join(recipients)
msg['Date'] = date_
msg['Subject'] = subject
msg.attach(MIMEText(body))
msg.attach(text_msg)
if attachment_files:
self.__atach_files(msg, attachment_files)
@@ -243,6 +243,11 @@ class User(Base, BaseModel):
else:
return Session.query(cls).filter(cls.username == username).one()
@classmethod
def get_by_api_key(cls, api_key):
return Session.query(cls).filter(cls.api_key == api_key).one()
def update_lastlogin(self):
"""Update user lastlogin"""
@@ -213,6 +213,10 @@ class UserModel(BaseModel):
self.sa.rollback()
raise
def reset_password_link(self, data):
from rhodecode.lib.celerylib import tasks, run_task
run_task(tasks.send_password_link, data['email'])
def reset_password(self, data):
run_task(tasks.reset_user_password, data['email'])
@@ -198,7 +198,8 @@ margin-bottom:5px !important;
-moz-border-radius: 0px 0px 8px 8px;
border-radius: 0px 0px 8px 8px;
height:37px;
background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367
background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367;
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
}
#header ul#logged-user li {
@@ -1383,6 +1384,13 @@ position: absolute;
margin-left: -16px;
width: 281px;
border-radius: 0 0 8px 8px;
#quick_login .password_forgoten{
padding-right:10px;
padding-top:10px;
float:left;
#quick_login div.form div.fields{
@@ -30,7 +30,7 @@
</div>
<div class="buttons">
${h.submit('sign_in','Sign In',class_="ui-button")}
<div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>${h.submit('sign_in','Sign In',class_="ui-button")}
@@ -28,7 +28,7 @@
<div class="nohighlight">
${h.submit('send','Reset my password',class_="ui-button")}
<div class="activation_msg">${_('Your new password will be send to matching email address')}</div>
<div class="activation_msg">${_('Password reset link will be send to matching email address')}</div>
new file 100644
Status change: