[gen] One can define statis attribute 'showHistory', being a method or a boolean value. It indicates if the history is visible or not. Added on the User, passwords fields on the main page. This way, when creating a user, those fields are used. When the user wants to change it own password, passwords on the 'passwords' page are then used.

This commit is contained in:
Gaetan Delannay 2014-11-25 14:56:38 +01:00
parent 1d721d61f4
commit 02a7be98ff
3 changed files with 55 additions and 24 deletions

View file

@ -1111,6 +1111,13 @@ class BaseMixin:
becomes: has this object an history for field p_name?'''
if not hasattr(self.aq_base, 'workflow_history') or \
not self.workflow_history: return
# Return False if the user can't consult the object history
klass = self.getClass()
if hasattr(klass, 'showHistory'):
show = klass.showHistory
if callable(show): show = klass.showHistory(self.appy())
if not show: return
# Get the object history
history = self.workflow_history['appy']
if not name:
for event in history:

View file

@ -151,25 +151,29 @@ class ModelClass:
# The User class ---------------------------------------------------------------
class User(ModelClass):
_appy_attributes = ['password1', 'password2', 'title', 'name', 'firstName',
'login', 'email', 'roles', 'source', 'groups', 'toTool']
'source', 'login', 'password3', 'password4', 'email',
'roles', 'groups', 'toTool']
# All methods defined below are fake. Real versions are in the wrapper.
# Passwords are on a specific page.
def showPassword(self): pass
def showPassword12(self): pass
def showPassword34(self): pass
def validatePassword(self): pass
pp = {'page': gen.Page('passwords', showNext=False, show=showPassword),
pp = {'page': gen.Page('passwords', showNext=False, show=showPassword12),
'width': 34, 'multiplicity': (1,1), 'format': gen.String.PASSWORD,
'show': showPassword}
'show': showPassword12}
password1 = gen.String(validator=validatePassword, **pp)
password2 = gen.String(**pp)
# All methods defined below are fake. Real versions are in the wrapper.
# Fields "password3" and "password4" are only shown when creating a user.
# After user creation, those fields are not used anymore; fields "password1"
# and "password2" above are then used to modify the password on a separate
# page.
pm = {'page': gen.Page('main', showPrevious=False), 'group': 'main',
'width': 34}
title = gen.String(show=False, indexed=True, **pm)
def showName(self): pass
name = gen.String(show=showName, **pm)
firstName = gen.String(show=showName, **pm)
def showEmail(self): pass
email = gen.String(show=showEmail, **pm)
# Where is this user stored? By default, in the ZODB. But the user can be
# stored in an external LDAP (source='ldap').
source = gen.String(show=False, default='zodb', layouts='f', **pm)
@ -178,7 +182,14 @@ class User(ModelClass):
def validateLogin(self): pass
login = gen.String(show=showLogin, validator=validateLogin,
indexed=True, **pm)
password3 = gen.String(validator=validatePassword, show=showPassword34,
format=gen.String.PASSWORD,
label=(None, 'password1'), **pm)
password4 = gen.String(show=showPassword34, format=gen.String.PASSWORD,
label=(None, 'password2'), **pm)
pm['multiplicity'] = (0, None)
def showEmail(self): pass
email = gen.String(show=showEmail, **pm)
def showRoles(self): pass
roles = gen.String(show=showRoles, indexed=True,
validator=gen.Selection('getGrantableRoles'), **pm)

View file

@ -86,15 +86,23 @@ class UserWrapper(AbstractWrapper):
return self.translate('password_too_short', mapping={'nb':5})
return True
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'
def showPassword12(self):
'''Fields "passwords1" and "password2", used only for modifying a
password on an existing user (on specific page "passwords"), must be
shown only for the user that can modify his password.'''
# On creation, fields "password3" and "password4" are used
if self.o.isTemporary(): return
# When the user itself (we don't check role Owner because a Manager can
# also own a User instance) wants to edit information about himself.
if (self.user.login == self.login) and (self.source == 'zodb'):
return 'edit'
def showPassword34(self):
'''Fields "password3" and "password4", used only on the main page for
entering a password when creating a new user, must be shown only when
the object is temporary.'''
if self.o.isTemporary(): return 'edit'
def encryptPassword(self, clearPassword):
'''Returns p_clearPassword, encrypted.'''
return self.o.getTool().acl_users._encryptPassword(clearPassword)
@ -106,7 +114,8 @@ class UserWrapper(AbstractWrapper):
if newPassword != None:
msgPart = 'changed'
else:
newPassword = self.getField('password1').generatePassword()
# Take any password field for generating a new password
newPassword = self.getField('password2').generatePassword()
msgPart = 'generated'
login = self.login
zopeUser = self.getZopeUser()
@ -176,13 +185,17 @@ class UserWrapper(AbstractWrapper):
def validate(self, new, errors):
'''Inter-field validation.'''
page = self.request.get('page', 'main')
self.o._oldLogin = None
if page == 'main':
if hasattr(new, 'password1') and (new.password1 != new.password2):
# Check that passwords match, either on page "passwords" (passwords 1
# and 2) or on page "main" (passwords 3 and 4).
for i in (1, 3):
passwordA = 'password%d' % i
passwordB = 'password%d' % (i + 1)
if hasattr(new, passwordA) and \
(getattr(new, passwordA) != getattr(new, passwordB)):
msg = self.translate('passwords_mismatch')
errors.password1 = msg
errors.password2 = msg
setattr(errors, passwordA, msg)
setattr(errors, passwordB, msg)
# Remember the previous login
if self.login: self.o._oldLogin = self.login
return self._callCustom('validate', new, errors)
@ -219,28 +232,28 @@ class UserWrapper(AbstractWrapper):
self.updateTitle()
self.ensureAdminIsManager()
if created:
# Create the corresponding Zope user.
# Create the corresponding Zope user
from AccessControl.User import User as ZopeUser
password = self.encryptPassword(self.password1)
password = self.encryptPassword(self.password3)
zopeUser = ZopeUser(login, password, self.roles, ())
# Add it in acl_users if it is a local user.
if isLocal: self.o.acl_users.data[login] = zopeUser
# Add it in self.o._zopeUser if it is a LDAP user
else: self.o._zopeUser = zopeUser
# Remove our own password copies
self.password1 = self.password2 = ''
self.password3 = self.password4 = ''
else:
# Update the login itself if the user has changed it.
# Update the login itself if the user has changed it
oldLogin = self.o._oldLogin
if oldLogin and (oldLogin != login):
self.setLogin(oldLogin, login)
del self.o._oldLogin
# Update roles at the Zope level.
# Update roles at the Zope level
zopeUser = self.getZopeUser()
zopeUser.roles = self.roles
# Update the password if the user has entered new ones.
# Update the password if the user has entered new ones
rq = self.request
if rq.has_key('password1'):
if rq.get('page', 'main') == 'passwords':
self.setPassword(rq['password1'])
self.password1 = self.password2 = ''
# "self" must be owned by its Zope user.