appy.gen: improvements in user management.

This commit is contained in:
Gaetan Delannay 2012-02-21 12:09:42 +01:00
parent 9394490d33
commit 9c5f92337b
10 changed files with 85 additions and 23 deletions

View file

@ -335,8 +335,7 @@ class ZopeInstaller:
(translation.id, poName))
# Execute custom installation code if any
if hasattr(appyTool, 'install'):
tool.executeAppyAction('install', reindex=False)
if hasattr(appyTool, 'onInstall'): appyTool.onInstall()
def configureSessions(self):
'''Configure the session machinery.'''

View file

@ -102,6 +102,16 @@ class ToolMixin(BaseMixin):
for elem in path.split('/'): res = res._getOb(elem)
return res
def showLanguageSelector(self):
'''We must show the language selector if the app config requires it and
it there is more than 2 supported languages. Moreover, on some pages,
switching the language is not allowed.'''
cfg = self.getProductConfig()
if not cfg.languageSelector: return
if len(cfg.languages) < 2: return
page = self.REQUEST.get('ACTUAL_URL').split('/')[-1]
return page not in ('edit', 'query', 'search')
def getLanguages(self):
'''Returns the supported languages. First one is the default.'''
return self.getProductConfig().languages
@ -111,6 +121,14 @@ class ToolMixin(BaseMixin):
p_code.'''
return languages.get(code)[2]
def getCssJs(self):
'''Returns the list of CSS and JS files to include in the main template.
The method ensures that appy.css and appy.js come first.'''
names = self.getPhysicalRoot().ui.objectIds('File')
names.remove('appy.js'); names.insert(0, 'appy.js')
names.remove('appy.css'); names.insert(0, 'appy.css')
return names
def consumeMessages(self):
'''Returns the list of messages to show to a web page and clean it in
the session.'''
@ -825,6 +843,11 @@ class ToolMixin(BaseMixin):
# --------------------------------------------------------------------------
# Authentication-related methods
# --------------------------------------------------------------------------
def _updateCookie(self, login, password):
cookieValue = base64.encodestring('%s:%s' % (login, password)).rstrip()
cookieValue = urllib.quote(cookieValue)
self.REQUEST.RESPONSE.setCookie('__ac', cookieValue, path='/')
def performLogin(self):
'''Logs the user in.'''
rq = self.REQUEST
@ -837,10 +860,7 @@ class ToolMixin(BaseMixin):
return self.goto(urlBack, msg)
# Perform the Zope-level authentication
login = rq.get('__ac_name', '')
password = rq.get('__ac_password', '')
cookieValue = base64.encodestring('%s:%s' % (login, password)).rstrip()
cookieValue = urllib.quote(cookieValue)
rq.RESPONSE.setCookie('__ac', cookieValue, path='/')
self._updateCookie(login, rq.get('__ac_password', ''))
user = self.acl_users.validate(rq)
if self.userIsAnon():
rq.RESPONSE.expireCookie('__ac', path='/')

View file

@ -85,7 +85,10 @@ class ModelClass:
elif isinstance(value, gen.Page):
value = 'pages["%s"]' % value.name
elif callable(value):
value = '%s.%s' % (wrapperName, value.__name__)
className = wrapperName
if (appyType.type == 'Ref') and appyType.isBack:
className = appyType.back.klass.__name__
value = '%s.%s' % (className, value.__name__)
typeArgs += '%s=%s,' % (name, value)
return '%s(%s)' % (appyType.__class__.__name__, typeArgs)
@ -144,10 +147,12 @@ class User(ModelClass):
password1 = gen.String(format=gen.String.PASSWORD, show=showPassword,
validator=validatePassword, **gm)
password2 = gen.String(format=gen.String.PASSWORD, show=showPassword, **gm)
email = gen.String(group='main', width=25)
def showEmail(self): pass
email = gen.String(show=showEmail, group='main', width=25)
gm['multiplicity'] = (0, None)
roles = gen.String(validator=gen.Selection('getGrantableRoles'),
indexed=True, **gm)
def showRoles(self): pass
roles = gen.String(show=showRoles, indexed=True,
validator=gen.Selection('getGrantableRoles'), **gm)
# The Group class --------------------------------------------------------------
class Group(ModelClass):
@ -163,7 +168,7 @@ class Group(ModelClass):
roles = gen.String(validator=gen.Selection('getGrantableRoles'),
multiplicity=(0,None), **m)
users = gen.Ref(User, multiplicity=(0,None), add=False, link=True,
back=gen.Ref(attribute='groups', show=True),
back=gen.Ref(attribute='groups', show=User.showRoles),
showHeaders=True, shownInfo=('title', 'login'))
# The Translation class --------------------------------------------------------

View file

@ -40,7 +40,7 @@ img {border: 0}
border-style: solid; border-width: 1px; border-color: grey; }
.top { height: 75px; margin-left: 3em; vertical-align: top;}
.lang { margin-right: 3px; }
.userStrip { background-color: #89A6B1; height: 30px;
.userStrip { background-color: #89A6B1; height: 40px;
border-top: 3px solid #405A64; border-bottom: 2px solid #5F7983; }
.login { margin-top: 2px; margin-bottom: 2px; color: white;}
.buttons { margin-left: 4px;}

BIN
gen/ui/banner.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

7
gen/ui/home.pt Normal file
View file

@ -0,0 +1,7 @@
<tal:main define="tool python: context.config">
<html metal:use-macro="context/ui/template/macros/main">
<div metal:fill-slot="content">
<span tal:replace="structure python: tool.translate('front_page_text')"/>
</div>
</html>
</tal:main>

View file

@ -14,7 +14,7 @@
<head>
<title tal:content="tool/getAppName"></title>
<tal:link repeat="name python: app.ui.objectIds('File')">
<tal:link repeat="name tool/getCssJs">
<link tal:condition="python: name.endswith('.css')"
rel="stylesheet" type="text/css" tal:attributes="href string:$appUrl/ui/$name"/>
<script tal:condition="python: name.endswith('.js')"
@ -31,12 +31,10 @@
<tr valign="top">
<td></td>
<tal:comment replace="nothing">Language selector (links or listbox)</tal:comment>
<td align="right"
tal:define="languages tool/getLanguages;
defaultLanguage python: languages[0];
suffix python: req.get('ACTUAL_URL').split('/')[-1];
asLinks python: len(languages) &lt;= 5"
tal:condition="python: len(languages) &gt;= 2 and (suffix not in ('edit', 'query', 'search'))">
<td align="right" tal:condition="tool/showLanguageSelector">
<tal:lgs define="languages tool/getLanguages;
defaultLanguage python: languages[0];
asLinks python: len(languages) &lt;= 5">
<table tal:condition="asLinks">
<tr>
<td tal:repeat="lang languages">
@ -54,6 +52,7 @@
tal:attributes="selected python:defaultLanguage == lang; value lang">
</option>
</select>
</tal:lgs>
</td>
</tr>
</table>

View file

@ -9,6 +9,10 @@ class GroupWrapper(AbstractWrapper):
if self.o.isTemporary(): return 'edit'
return 'view'
def showGroups(self):
'''Only the admin can view or edit roles.'''
return self.user.has_role('Manager')
def validateLogin(self, login):
'''Is this p_login valid?'''
return True

View file

@ -9,6 +9,16 @@ class UserWrapper(AbstractWrapper):
if self.o.isTemporary(): return 'edit'
return 'view'
def showEmail(self):
'''In most cases, email is the login. Show the field only if it is not
the case.'''
email = self.email
return email and (email != self.login)
def showRoles(self):
'''Only the admin can view or edit roles.'''
return self.user.has_role('Manager')
def validateLogin(self, login):
'''Is this p_login valid?'''
# The login can't be the id of the whole site or "admin"
@ -28,8 +38,11 @@ class UserWrapper(AbstractWrapper):
def showPassword(self):
'''When must we show the 2 fields for entering a password ?'''
# When someone creates the user
if self.o.isTemporary(): return 'edit'
return False
# When the user itself (which is Owner of the object representing him)
# wants to edit information about himself.
if self.user.has_role('Owner', self): return 'edit'
def getGrantableRoles(self):
'''Returns the list of roles that the admin can grant to a user.'''
@ -64,9 +77,16 @@ class UserWrapper(AbstractWrapper):
# granted to it.
zopeUser.groups = PersistentMapping()
else:
# Updates roles at the Zope level.
# Update roles at the Zope level.
zopeUser = aclUsers.getUserById(login)
zopeUser.roles = self.roles
# Update the password if the user has entered new ones.
rq = self.request
if rq.has_key('password1'):
zopeUser.__ = aclUsers._encryptPassword(rq['password1'])
# Update the cookie value
self.tool.o._updateCookie(login, rq['password1'])
self.password1 = self.password2 = ''
# "self" must be owned by its Zope user.
if 'Owner' not in self.o.get_local_roles_for_userid(login):
self.o.manage_addLocalRoles(login, ('Owner',))