@@ -291,12 +291,16 @@ def make_map(config):
rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
action='register')
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',
conditions=dict(function=check_repo))
rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
@@ -126,14 +126,14 @@ class LoginController(BaseController):
user_model = UserModel()
if request.POST:
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'))
except formencode.Invalid, errors:
return htmlfill.render(
render('/password_reset.html'),
@@ -141,11 +141,28 @@ class LoginController(BaseController):
errors=errors.error_dict or {},
prefix_error=False,
encoding="UTF-8")
return render('/password_reset.html')
def password_reset_confirmation(self):
if request.GET and request.GET.get('key'):
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()
log.info('Logging out and setting user as Empty')
redirect(url('home'))
@@ -31,13 +31,13 @@ import logging
from os.path import dirname as dn, join as jn
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
from rhodecode.lib.celerylib import run_task, locked_task, str2bool, \
__get_lockkey, LockHeld, DaemonLock
from rhodecode.lib.helpers import person
@@ -246,12 +246,51 @@ def get_commits_stats(repo_name, ts_min_
run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
return True
except LockHeld:
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
def reset_user_password(user_email):
@@ -277,14 +316,14 @@ 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))
@@ -71,19 +71,25 @@ class SmtpMailer(object):
#but only if we have them
if self.user and self.passwd:
smtp_serv.login(self.user, self.passwd)
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)
smtp_serv.sendmail(self.mail_from, recipients, msg.as_string())
logging.info('MAIL SEND TO: %s' % recipients)
@@ -240,12 +240,17 @@ class User(Base, BaseModel):
def by_username(cls, username, case_insensitive=False):
if case_insensitive:
return Session.query(cls).filter(cls.username.like(username)).one()
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"""
self.last_login = datetime.datetime.now()
Session.add(self)
Session.commit()
@@ -210,12 +210,16 @@ class UserModel(BaseModel):
self.sa.commit()
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'])
def fill_data(self, auth_user, user_id=None, api_key=None):
@@ -195,13 +195,14 @@ padding:0 10px;
margin-bottom:5px !important;
-webkit-border-radius: 0px 0px 8px 8px;
-khtml-border-radius: 0px 0px 8px 8px;
-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 {
list-style:none;
float:left;
margin:8px 0 0;
@@ -1380,12 +1381,19 @@ background-color: rgb(0, 51, 103);
z-index: 999;
height: 150px;
position: absolute;
margin-left: -16px;
width: 281px;
border-radius: 0 0 8px 8px;
#quick_login .password_forgoten{
padding-right:10px;
padding-top:10px;
#quick_login div.form div.fields{
padding-top: 2px;
padding-left:10px;
@@ -27,13 +27,13 @@
<div class="input">
${h.password('password',class_='focus',size=40)}
</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")}
${h.end_form()}
<script type="text/javascript">
YUE.on('quick_login_link','click',function(e){
@@ -25,13 +25,13 @@
<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: