[gen] Implemented a mechanism 'forgot password?'.
This commit is contained in:
parent
8a5ca81746
commit
ad14c1258c
|
@ -487,6 +487,14 @@ class ZopeGenerator(Generator):
|
|||
msg('enable_cookies', '', msg.ENABLE_COOKIES),
|
||||
msg('page_previous', '', msg.PAGE_PREVIOUS),
|
||||
msg('page_next', '', msg.PAGE_NEXT),
|
||||
msg('forgot_password', '', msg.FORGOT_PASSWORD),
|
||||
msg('ask_password_reinit', '', msg.ASK_PASSWORD_REINIT),
|
||||
msg('reinit_mail_sent', '', msg.REINIT_MAIL_SENT),
|
||||
msg('reinit_password', '', msg.REINIT_PASSWORD),
|
||||
msg('reinit_password_body', '', msg.REINIT_PASSWORD_BODY),
|
||||
msg('new_password', '', msg.NEW_PASSWORD),
|
||||
msg('new_password_body', '', msg.NEW_PASSWORD_BODY),
|
||||
msg('new_password_sent', '', msg.NEW_PASSWORD_SENT),
|
||||
]
|
||||
# Create a label for every role added by this application
|
||||
for role in self.getAllUsedRoles():
|
||||
|
|
|
@ -4,11 +4,12 @@ from appy.shared import mimeTypes
|
|||
from appy.shared.utils import getOsTempFolder, sequenceTypes
|
||||
from appy.shared.data import languages
|
||||
import appy.gen
|
||||
from appy.gen import Type, Search, Selection
|
||||
from appy.gen import Type, Search, Selection, String
|
||||
from appy.gen.utils import SomeObjects, getClassName
|
||||
from appy.gen.mixins import BaseMixin
|
||||
from appy.gen.wrappers import AbstractWrapper
|
||||
from appy.gen.descriptors import ClassDescriptor
|
||||
from appy.gen.mail import sendMail
|
||||
try:
|
||||
from AccessControl.ZopeSecurityPolicy import _noroles
|
||||
except ImportError:
|
||||
|
@ -1042,4 +1043,68 @@ class ToolMixin(BaseMixin):
|
|||
if hasattr(self.o.aq_base, 'pages') and self.o.pages:
|
||||
return [self.getObject(uid) for uid in self.o.pages ]
|
||||
return ()
|
||||
|
||||
def askPasswordReinit(self):
|
||||
'''A user (anonymmous) does not remember its password. Here we will
|
||||
send him a mail containing a link that will trigger password
|
||||
re-initialisation.'''
|
||||
login = self.REQUEST.get('login').strip()
|
||||
appyTool = self.appy()
|
||||
user = appyTool.search1('User', login=login, noSecurity=True)
|
||||
msg = self.translate('reinit_mail_sent')
|
||||
backUrl = self.REQUEST['HTTP_REFERER']
|
||||
if not user:
|
||||
# Return the message nevertheless. This way, malicious users can't
|
||||
# deduce information about existing users.
|
||||
return self.goto(backUrl, msg)
|
||||
# If login is an email, use it. Else, use user.email instead.
|
||||
email = user.login
|
||||
if not String.EMAIL.match(email):
|
||||
email = user.email
|
||||
if not email:
|
||||
# Impossible to re-initialise the password.
|
||||
return self.goto(backUrl, msg)
|
||||
# Create a temporary file whose name is the user login and whose
|
||||
# content is a generated token.
|
||||
f = file(os.path.join(getOsTempFolder(), login), 'w')
|
||||
token = String().generatePassword()
|
||||
f.write(token)
|
||||
f.close()
|
||||
# Send an email
|
||||
initUrl = '%s/doPasswordReinit?login=%s&token=%s' % \
|
||||
(self.absolute_url(), login, token)
|
||||
subject = self.translate('reinit_password')
|
||||
map = {'url':initUrl, 'siteUrl':self.getSiteUrl()}
|
||||
body= self.translate('reinit_password_body', mapping=map, format='text')
|
||||
sendMail(appyTool, email, subject, body)
|
||||
return self.goto(backUrl, msg)
|
||||
|
||||
def doPasswordReinit(self):
|
||||
'''Performs the password re-initialisation.'''
|
||||
rq = self.REQUEST
|
||||
login = rq['login']
|
||||
token = rq['token']
|
||||
# Check if such token exists in temp folder
|
||||
tokenFile = os.path.join(getOsTempFolder(), login)
|
||||
if os.path.exists(tokenFile):
|
||||
f = file(tokenFile)
|
||||
storedToken = f.read()
|
||||
f.close()
|
||||
if storedToken == token:
|
||||
# Generate a new password for this user
|
||||
appyTool = self.appy()
|
||||
user = appyTool.search1('User', login=login, noSecurity=True)
|
||||
newPassword = user.setPassword()
|
||||
# Send the new password by email
|
||||
email = login
|
||||
if not String.EMAIL.match(email):
|
||||
email = user.email
|
||||
subject = self.translate('new_password')
|
||||
siteUrl = self.getSiteUrl()
|
||||
map = {'password': newPassword, 'siteUrl': siteUrl}
|
||||
body = self.translate('new_password_body', mapping=map,
|
||||
format='text')
|
||||
sendMail(appyTool, email, subject, body)
|
||||
os.remove(tokenFile)
|
||||
return self.goto(siteUrl, self.translate('new_password_sent'))
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
15
gen/po.py
15
gen/po.py
|
@ -136,6 +136,21 @@ class PoMessage:
|
|||
ENABLE_COOKIES = 'You must enable cookies before you can log in.'
|
||||
PAGE_PREVIOUS = 'Previous page'
|
||||
PAGE_NEXT = 'Next page'
|
||||
FORGOT_PASSWORD = 'Forgot password?'
|
||||
ASK_PASSWORD_REINIT = 'Ask new password'
|
||||
REINIT_MAIL_SENT = 'A mail has been sent to you. Please follow the ' \
|
||||
'instructions from this email.'
|
||||
REINIT_PASSWORD = 'Password re-initialisation'
|
||||
REINIT_PASSWORD_BODY = 'Hello,<br/><br/>A password re-initialisation ' \
|
||||
'has been requested, tied to this email address, for the website ' \
|
||||
'${siteUrl}. If you are not at the origin of this request, please ' \
|
||||
'ignore this email. Else, click on the link below to receive a new ' \
|
||||
'password.<br/><br/>${url}'
|
||||
NEW_PASSWORD = 'Your new password'
|
||||
NEW_PASSWORD_BODY = 'Hello,<br/><br/>The new password you have ' \
|
||||
'requested for website ${siteUrl} is ${password}<br/>' \
|
||||
'<br/>Best regards.'
|
||||
NEW_PASSWORD_SENT = 'Your new password has been sent to you by email.'
|
||||
|
||||
def __init__(self, id, msg, default, fuzzy=False, comments=[],
|
||||
niceDefault=False):
|
||||
|
|
|
@ -67,6 +67,7 @@ img { border: 0; vertical-align: middle}
|
|||
border-radius: 2px 2px 2px 2px; box-shadow: 0 2px 4px #A9A9A9;}
|
||||
.focus td { padding: 4px 0px 4px 4px }
|
||||
.discreet { font-size: 90%; }
|
||||
.lostPassword a { font-size: 90%; color: white; padding-left: 1em;}
|
||||
.portlet { width: 150px; border-right: 1px solid #5F7983;}
|
||||
.portletContent { margin: 9px; }
|
||||
.portletTitle { font-weight: bold; font-size: 110%; margin-bottom: 4px;}
|
||||
|
|
|
@ -451,6 +451,19 @@ function doConfirm() {
|
|||
}
|
||||
}
|
||||
|
||||
var wrongTextInput = '#ff934a none';
|
||||
// Function triggered when the user ask password reinitialisation
|
||||
function doAskPasswordReinit() {
|
||||
// Check that the user has typed a login
|
||||
var theForm = document.getElementById('askPasswordReinitForm');
|
||||
var login = theForm.login.value.replace(' ', '');
|
||||
if (!login) { theForm.login.style.background = wrongTextInput; }
|
||||
else {
|
||||
closePopup('askPasswordReinitPopup');
|
||||
theForm.submit();
|
||||
}
|
||||
}
|
||||
|
||||
// Function that finally posts the edit form after the user has confirmed that
|
||||
// she really wants to post it.
|
||||
function postConfirmedEditForm() {
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
<div id="grey" class="grey"></div>
|
||||
|
||||
<tal:comment replace="nothing">Popup for confirming an action</tal:comment>
|
||||
<div id="confirmActionPopup" class="popup">
|
||||
<div id="confirmActionPopup" class="popup">
|
||||
<form id="confirmActionForm" method="post">
|
||||
<div align="center">
|
||||
<p id="appyConfirmText"></p>
|
||||
|
@ -96,7 +96,22 @@
|
|||
tal:attributes="value python:_('no')"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<tal:comment replace="nothing">Popup for reinitialing the password</tal:comment>
|
||||
<div id="askPasswordReinitPopup" class="popup" tal:condition="isAnon">
|
||||
<form id="askPasswordReinitForm" method="post"
|
||||
tal:attributes="action python: tool.absolute_url() + '/askPasswordReinit'">
|
||||
<div align="center">
|
||||
<p tal:content="python: _('app_login')"></p>
|
||||
<input type="text" size="35" name="login" id="login" value=""/>
|
||||
<br/><br/>
|
||||
<input type="button" onClick="doAskPasswordReinit()"
|
||||
tal:attributes="value python:_('ask_password_reinit')"/>
|
||||
<input type="button" value="No" onClick="closePopup('askPasswordReinitPopup')"
|
||||
tal:attributes="value python:_('object_cancel')"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tal:comment replace="nothing">The user strip</tal:comment>
|
||||
|
@ -108,23 +123,28 @@
|
|||
<tal:comment replace="nothing">The user login form for anonymous users</tal:comment>
|
||||
<table align="center" tal:condition="python: isAnon and ('/temp_folder/' not in req['ACTUAL_URL'])"
|
||||
class="login">
|
||||
<tr><td class="userStripText">
|
||||
<form name="loginform" method="post"
|
||||
<tr>
|
||||
<td class="userStripText">
|
||||
<form name="loginform" method="post"
|
||||
tal:attributes="action python: tool.absolute_url() + '/performLogin'">
|
||||
|
||||
<input type="hidden" name="js_enabled" id="js_enabled" value="0"/>
|
||||
<input type="hidden" name="cookies_enabled" id="cookies_enabled" value=""/>
|
||||
<input type="hidden" name="login_name" id="login_name" value=""/>
|
||||
<input type="hidden" name="pwd_empty" id="pwd_empty" value="0"/>
|
||||
<input type="hidden" name="js_enabled" id="js_enabled" value="0"/>
|
||||
<input type="hidden" name="cookies_enabled" id="cookies_enabled" value=""/>
|
||||
<input type="hidden" name="login_name" id="login_name" value=""/>
|
||||
<input type="hidden" name="pwd_empty" id="pwd_empty" value="0"/>
|
||||
|
||||
<span tal:replace="python: _('app_login')"/>
|
||||
<input type="text" size="25" name="__ac_name" id="__ac_name" value=""/>
|
||||
<span tal:replace="python: _('app_password')"/>
|
||||
<input type="password" size="25" name="__ac_password" id="__ac_password"/>
|
||||
<input type="submit" name="submit" onclick="setLoginVars()"
|
||||
tal:define="label python: _('app_connect')" tal:attributes="value label; alt label;"/>
|
||||
</form>
|
||||
</td></tr>
|
||||
<span tal:replace="python: _('app_login')"/>
|
||||
<input type="text" size="25" name="__ac_name" id="__ac_name" value=""/>
|
||||
<span tal:replace="python: _('app_password')"/>
|
||||
<input type="password" size="25" name="__ac_password" id="__ac_password"/>
|
||||
<input type="submit" name="submit" onclick="setLoginVars()"
|
||||
tal:define="label python: _('app_connect')" tal:attributes="value label; alt label;"/>
|
||||
</form>
|
||||
</td>
|
||||
<td class="lostPassword">
|
||||
<a href="javascript: openPopup('askPasswordReinitPopup')"
|
||||
tal:content="python: _('forgot_password')"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<tal:comment replace="nothing">User info and controls for authenticated users</tal:comment>
|
||||
<table tal:condition="not: isAnon" class="buttons" width="99%">
|
||||
|
|
Loading…
Reference in a new issue