[gen] Added Config.discreetLogin allowing to put a discreet link on the main page for logging in, instead of the login form in the central strip, for sites where logged users do not represent the majority of visitors (only some admins).

This commit is contained in:
Gaetan Delannay 2013-05-10 12:16:57 +02:00
parent 8a0ee2c131
commit 820d3ef241
11 changed files with 94 additions and 86 deletions

View file

@ -38,4 +38,5 @@ class Object:
return res.encode('utf-8') return res.encode('utf-8')
def __nonzero__(self): def __nonzero__(self):
return bool(self.__dict__) return bool(self.__dict__)
def get(self, name, default=None): return getattr(self, name, default)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -3013,6 +3013,10 @@ class Config:
self.activateForgotPassword = True self.activateForgotPassword = True
# Enable session timeout? # Enable session timeout?
self.enableSessionTimeout = False self.enableSessionTimeout = False
# If the following field is True, the login/password widget will be
# discreet. This is for sites where authentication is not foreseen for
# the majority of visitors (just for some administrators).
self.discreetLogin = False
# When using Ogone, place an instance of appy.gen.ogone.OgoneConfig in # When using Ogone, place an instance of appy.gen.ogone.OgoneConfig in
# the field below. # the field below.
self.ogone = None self.ogone = None

View file

@ -604,6 +604,7 @@ class ZopeGenerator(Generator):
repls['languageSelector'] = self.config.languageSelector repls['languageSelector'] = self.config.languageSelector
repls['sourceLanguage'] = self.config.sourceLanguage repls['sourceLanguage'] = self.config.sourceLanguage
repls['enableSessionTimeout'] = self.config.enableSessionTimeout repls['enableSessionTimeout'] = self.config.enableSessionTimeout
repls['discreetLogin'] = self.config.discreetLogin
repls['ogone'] = repr(self.config.ogone) repls['ogone'] = repr(self.config.ogone)
repls['googleAnalyticsId'] = repr(self.config.googleAnalyticsId) repls['googleAnalyticsId'] = repr(self.config.googleAnalyticsId)
repls['activateForgotPassword'] = self.config.activateForgotPassword repls['activateForgotPassword'] = self.config.activateForgotPassword

View file

@ -89,9 +89,13 @@ class ToolMixin(BaseMixin):
'inline;filename="%s"' % res.name) 'inline;filename="%s"' % res.name)
return res.content return res.content
def getAttr(self, name): def getAttr(self, name, source='appy'):
'''Gets attribute named p_name.''' '''Gets attribute named p_name.'''
return getattr(self.appy(), name, None) if source == 'config':
obj = self.getProductConfig()
else:
obj = self.appy()
return getattr(obj, name, None)
def getAppName(self): def getAppName(self):
'''Returns the name of the application.''' '''Returns the name of the application.'''

View file

@ -49,6 +49,7 @@ languageSelector = <!languageSelector!>
sourceLanguage = '<!sourceLanguage!>' sourceLanguage = '<!sourceLanguage!>'
activateForgotPassword = <!activateForgotPassword!> activateForgotPassword = <!activateForgotPassword!>
enableSessionTimeout = <!enableSessionTimeout!> enableSessionTimeout = <!enableSessionTimeout!>
discreetLogin = <!discreetLogin!>
ogone = <!ogone!> ogone = <!ogone!>
googleAnalyticsId = <!googleAnalyticsId!> googleAnalyticsId = <!googleAnalyticsId!>

View file

@ -55,15 +55,15 @@ img { border: 0; vertical-align: middle }
border-style: solid; border-width: 1px; border-color: grey } border-style: solid; border-width: 1px; border-color: grey }
.top { height: 89px; margin-left: 3em; vertical-align: top } .top { height: 89px; margin-left: 3em; vertical-align: top }
.lang { margin-right: 6px } .lang { margin-right: 6px }
.userStrip { background-color: #6282B3; height: 35px; .userStrip { background-color: #6282B3; border-top: 3px solid #034984;
border-top: 3px solid #034984; border-bottom: 2px solid #034984 } border-bottom: 2px solid #034984 }
.userStripText { padding: 0 0.3em 0 0.3em; color: white } .userStripText { padding: 0 0.3em 0 0.3em; color: white }
.userStrip a { color: #e7e7e7 } .userStrip a { color: #e7e7e7 }
.userStrip a:visited { color: #e7e7e7 } .userStrip a:visited { color: #e7e7e7 }
.navigate { border-bottom: 1px solid #5F7983; .navigate { border-bottom: 1px solid #5F7983;
background-color: #dbdde1; font-weight: bold } background-color: #dbdde1; font-weight: bold }
.navigate td { padding: 4px 9px } .navigate td { padding: 4px 9px }
.login { margin-top: 2px; margin-bottom: 2px; color: black } .login { margin: 3px; color: black }
.buttons { margin-left: 4px } .buttons { margin-left: 4px }
.fakeButton { border: 1px solid #D7DEE4; background-color: #fde8e0; .fakeButton { border: 1px solid #D7DEE4; background-color: #fde8e0;
padding: 0px 8px 2px; padding: 0px 8px 2px;
@ -79,7 +79,7 @@ img { border: 0; vertical-align: middle }
.discreet { font-size: 90%; color: grey } .discreet { font-size: 90%; color: grey }
.title { color: #BA9440 } .title { color: #BA9440 }
.breadcrumb { color: #BA9440; font-size: 13px } .breadcrumb { color: #BA9440; font-size: 13px }
.lostPassword a { font-size: 90%; color: white; padding-left: 1em } .lostPassword { font-size: 90%; color: white; padding-left: 1em }
.portlet { width: 150px; border-right: 1px solid #5F7983; .portlet { width: 150px; border-right: 1px solid #5F7983;
background-color: #ededed } background-color: #ededed }
.portletContent { margin: 4px 9px } .portletContent { margin: 4px 9px }
@ -133,7 +133,7 @@ img { border: 0; vertical-align: middle }
.history th { font-style: italic; text-align: left; padding: 0 5px 0 5px } .history th { font-style: italic; text-align: left; padding: 0 5px 0 5px }
.topSpace { margin-top: 15px } .topSpace { margin-top: 15px }
.bottomSpace { margin-bottom: 15px } .bottomSpace { margin-bottom: 15px }
.pageLink { padding-left: 8px } .pageLink { margin-right: 8px }
.footer { font-size: 95% } .footer { font-size: 95% }
.footer td { background-color: #CBCBC9; border-top: 1px solid grey; .footer td { background-color: #CBCBC9; border-top: 1px solid grey;
padding: 0.4em 1em 0.5em } padding: 0.4em 1em 0.5em }

View file

@ -32,6 +32,15 @@ function setLoginVars() {
else emptyPassword.value = '0'; else emptyPassword.value = '0';
} }
function showLoginForm() {
// Hide the login link.
var loginLink = document.getElementById('loginLink');
loginLink.style.display = "none";
// Displays the login form.
var loginFields = document.getElementById('loginFields');
loginFields.style.display = "inline";
}
var isIe = (navigator.appName == "Microsoft Internet Explorer"); var isIe = (navigator.appName == "Microsoft Internet Explorer");
function getElementsHavingName(tag, name) { function getElementsHavingName(tag, name) {

View file

@ -5,3 +5,4 @@ ul li { background-image: url("ui/lirtl.gif");
.portlet { border-right: none; border-left: 1px solid #5F7983 } .portlet { border-right: none; border-left: 1px solid #5F7983 }
.lang { margin-right: 0px; margin-left: 6px; } .lang { margin-right: 0px; margin-left: 6px; }
.cellGap { padding-left: 0.4em; padding-right: 0;} .cellGap { padding-left: 0.4em; padding-right: 0;}
.pageLink { margin-right: 0px; margin-left: 8px }

View file

@ -1 +1,2 @@
<span metal:define-macro="icons"></span> <metal:i define-macro="icons"></metal:i>
<metal:l define-macro="links"></metal:l>

View file

@ -15,6 +15,7 @@
layoutType tool/getLayoutType; layoutType tool/getLayoutType;
contextObj python: tool.getPublishedObject(layoutType); contextObj python: tool.getPublishedObject(layoutType);
dir python: tool.getLanguageDirection(lang); dir python: tool.getLanguageDirection(lang);
discreetLogin python: tool.getAttr('discreetLogin', source='config');
dleft python: (dir == 'ltr') and 'left' or 'right'; dleft python: (dir == 'ltr') and 'left' or 'right';
dright python: (dir == 'ltr') and 'right' or 'left'; dright python: (dir == 'ltr') and 'right' or 'left';
x python: resp.setHeader('Content-type', 'text/html;;charset=UTF-8'); x python: resp.setHeader('Content-type', 'text/html;;charset=UTF-8');
@ -39,7 +40,6 @@
type="text/javascript" tal:content="gaCode"></script> type="text/javascript" tal:content="gaCode"></script>
<tal:comment replace="nothing">Grey background shown when popups are shown</tal:comment> <tal:comment replace="nothing">Grey background shown when popups are shown</tal:comment>
<div id="grey" class="grey"></div> <div id="grey" class="grey"></div>
<tal:comment replace="nothing">Popup for confirming an action</tal:comment> <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"> <form id="confirmActionForm" method="post">
@ -81,38 +81,35 @@
<tr class="top" metal:define-slot="top"> <tr class="top" metal:define-slot="top">
<td tal:define="bannerName python: (dir == 'ltr') and 'banner' or 'bannerrtl'" <td tal:define="bannerName python: (dir == 'ltr') and 'banner' or 'bannerrtl'"
tal:attributes="style python: 'background-image: url(%s/ui/%s.jpg)' % (appUrl, bannerName)"> tal:attributes="style python: 'background-image: url(%s/ui/%s.jpg)' % (appUrl, bannerName)">
<table width="100%" style="margin-top: 4px"> <tal:comment replace="nothing">Top links</tal:comment>
<tr valign="top" tal:define="pages tool/getMainPages"> <div style="margin-top: 4px"
<tal:comment replace="nothing">Links to main pages</tal:comment> tal:define="pages tool/getMainPages" tal:attributes="align dright">
<td tal:condition="pages"><a tal:repeat="page pages" class="pageLink" <tal:comment replace="nothing">Icon "home"</tal:comment>
tal:content="page/title" tal:attributes="href page/absolute_url"></a> <a class="pageLink" tal:attributes="href appUrl; title python: _('app_home')">
</td> <img tal:attributes="src string: $appUrl/ui/home.gif" style="margin-right: 3px"/>
<tal:comment replace="nothing">Language selector (links or listbox)</tal:comment> </a>
<td tal:condition="tool/showLanguageSelector" tal:attributes="align dright"> <tal:comment replace="nothing">Additional links (or icons) from icons.pt</tal:comment>
<tal:lgs define="languages tool/getLanguages; <metal:call use-macro="app/ui/icons/macros/links"/>
defaultLanguage python: languages[0]; <tal:comment replace="nothing">Top-level pages</tal:comment>
asLinks python: len(languages) &lt;= 8"> <a tal:repeat="page pages" class="pageLink"
<table tal:condition="asLinks"> tal:content="page/title" tal:attributes="href page/absolute_url"></a>
<tr> <tal:comment replace="nothing">Connect link if discreet login</tal:comment>
<td tal:repeat="lang languages"> <a id="loginLink" name="loginLink" onclick="showLoginForm()" class="pageLink" style="cursor:pointer"
<a class="lang" tal:condition="python: isAnon and discreetLogin" tal:content="python: _('app_connect')">
tal:attributes="href string: $appUrl/config/changeLanguage?language=$lang; </a>
title python: tool.getLanguageName(lang)" <tal:comment replace="nothing">Language selector</tal:comment>
tal:content="python: lang"></a> <tal:lg condition="tool/showLanguageSelector">
</td> <select class="pageLink"
</tr> tal:define="languages tool/getLanguages;
</table> defaultLanguage python: languages[0]"
<select tal:condition="not: asLinks" tal:attributes="onchange string:window.location='$appUrl/config/changeLanguage?language=' + this.options[this.selectedIndex].value">
tal:attributes="onchange string:window.location='$appUrl/config/changeLanguage?language=' + this.options[this.selectedIndex].value"> <option tal:repeat="lg languages"
<option tal:repeat="lang languages" tal:content="python: tool.getLanguageName(lg)"
tal:content="python: tool.getLanguageName(lang)" tal:attributes="selected python:lang == lg; value lg">
tal:attributes="selected python:defaultLanguage == lang; value lang"> </option>
</option> </select>
</select> </tal:lg>
</tal:lgs> </div>
</td>
</tr>
</table>
</td> </td>
</tr> </tr>
<tal:comment replace="nothing">The message strip</tal:comment> <tal:comment replace="nothing">The message strip</tal:comment>
@ -128,58 +125,46 @@
<td> <td>
<table class="userStrip" width="100%"> <table class="userStrip" width="100%">
<tr> <tr>
<td> <tal:comment replace="nothing">The user login form for anonymous users</tal:comment>
<tal:comment replace="nothing">The user login form for anonymous users</tal:comment> <td align="center"
<table align="center" tal:condition="python: isAnon and ('/temp_folder/' not in req['ACTUAL_URL'])" tal:condition="python: isAnon and ('/temp_folder/' not in req['ACTUAL_URL'])">
class="login"> <form id="loginForm" name="loginForm" method="post" class="login"
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"/>
<tal:comment replace="nothing">The login fields, directly shown or not (depends on discreetLogin)</tal:comment>
<span id="loginFields" name="loginFields"
tal:attributes="style python: discreetLogin and 'display:none' or 'display:block'">
<span class="userStripText" tal:content="python: _('app_login')"/>
<input type="text" name="__ac_name" id="__ac_name" value="" style="width: 142px"/>&nbsp;
<span class="userStripText" tal:content="python: _('app_password')"/>
<input type="password" name="__ac_password" id="__ac_password" style="width: 142px"/>
<input type="submit" name="submit" onclick="setLoginVars()"
tal:define="label python: _('app_connect')" tal:attributes="value label; alt label"/>
<tal:comment replace="nothing">Forgot password?</tal:comment>
<a class="lostPassword" href="javascript: openPopup('askPasswordReinitPopup')"
tal:condition="tool/showForgotPassword"
tal:content="python: _('forgot_password')">
</a>
</span>
</form>
</td>
<tal:comment replace="nothing">User info and controls for authenticated users</tal:comment>
<td tal:condition="not: isAnon">
<table class="buttons" width="99%">
<tr> <tr>
<td> <td>
<!-- Go home --> <tal:comment replace="nothing">Config</tal:comment>
<a tal:attributes="href appUrl; title python: _('app_home')">
<img tal:attributes="src string: $appUrl/ui/home.gif" style="margin-right: 3px"/>
</a>
<tal:comment replace="nothing">Additional icons can be added here by redefining icons.pt</tal:comment>
<metal:call use-macro="app/ui/icons/macros/icons"/>
</td>
<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"/>
<span tal:replace="python: _('app_login')"/>&nbsp;
<input type="text" name="__ac_name" id="__ac_name" value="" style="width: 142px"/>&nbsp;
<span tal:replace="python: _('app_password')"/>&nbsp;
<input type="password" name="__ac_password" id="__ac_password" style="width: 142px"/>
<input type="submit" name="submit" onclick="setLoginVars()"
tal:define="label python: _('app_connect')" tal:attributes="value label; alt label;"/>
</form>
</td>
<td class="lostPassword" tal:condition="tool/showForgotPassword">
<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%">
<tr>
<td>
<!-- Go home -->
<a tal:attributes="href appUrl; title python: _('app_home')">
<img tal:attributes="src string: $appUrl/ui/home.gif"/>
</a>
<!-- Config -->
<a tal:condition="python: user.has_role('Manager')" <a tal:condition="python: user.has_role('Manager')"
tal:attributes="href python: tool.getUrl(nav=''); tal:attributes="href python: tool.getUrl(nav='');
title python: _('%sTool' % appName)"> title python: _('%sTool' % appName)">
<img tal:attributes="src string:$appUrl/ui/appyConfig.gif"/> <img tal:attributes="src string:$appUrl/ui/appyConfig.gif"/>
</a> </a>
<tal:comment replace="nothing">Additional icons can be added here by redefining icons.pt</tal:comment> <tal:comment replace="nothing">Additional icons from icons.pt</tal:comment>
<metal:call use-macro="app/ui/icons/macros/icons"/> <metal:call use-macro="app/ui/icons/macros/icons"/>
<!-- Logout --> <tal:comment replace="nothing">Log out</tal:comment>
<a tal:attributes="href python: tool.absolute_url() + '/performLogout'; <a tal:attributes="href python: tool.absolute_url() + '/performLogout';
title python: _('app_logout')"> title python: _('app_logout')">
<img tal:attributes="src string: $appUrl/ui/logout.gif"/> <img tal:attributes="src string: $appUrl/ui/logout.gif"/>

View file

@ -74,8 +74,9 @@ class UserWrapper(AbstractWrapper):
# The user for which we change the password is the currently logged # The user for which we change the password is the currently logged
# user. So update the authentication cookie, too. # user. So update the authentication cookie, too.
tool._updateCookie(login, newPassword) tool._updateCookie(login, newPassword)
loggedUser = self.user.getId() or 'system|anon'
self.log('Password %s by "%s" for "%s".' % \ self.log('Password %s by "%s" for "%s".' % \
(msgPart, self.user.getId(), login)) (msgPart, loggedUser, login))
return newPassword return newPassword
def checkPassword(self, clearPassword): def checkPassword(self, clearPassword):