diff --git a/browser/form.py b/browser/form.py index 39d864a..007d2c3 100644 --- a/browser/form.py +++ b/browser/form.py @@ -43,6 +43,7 @@ from cybertools.browser.form import FormController from cybertools.composer.interfaces import IInstance from cybertools.composer.schema.interfaces import ISchemaFactory from cybertools.composer.schema.browser.common import schema_macros, schema_edit_macros +from cybertools.composer.schema.schema import FormState from cybertools.typology.interfaces import IType, ITypeManager from loops.common import adapted from loops.concept import Concept, ResourceRelation @@ -61,12 +62,11 @@ from loops.versioning.interfaces import IVersionable # forms class ObjectForm(NodeView): - """ Abstract base class for forms. + """ Abstract base class for resource or concept forms using Dojo dialog. """ template = ViewPageTemplateFile('form_macros.pt') - - _isSetUp = False + formState = FormState() # dummy, don't update! def __init__(self, context, request): super(ObjectForm, self).__init__(context, request) @@ -79,12 +79,12 @@ class ObjectForm(NodeView): def typeInterface(self): return IType(self.context).typeInterface or ITextDocument - @property - def schemaMacros(self): + @Lazy + def fieldRenderers(self): return schema_macros.macros - @property - def schemaEditMacros(self): + @Lazy + def fieldEditRenderers(self): return schema_edit_macros.macros @Lazy @@ -211,7 +211,7 @@ class CreateObjectForm(ObjectForm, Form): class InnerForm(CreateObjectForm): @property - def macro(self): return self.schemaMacros['fields'] + def macro(self): return self.fieldRenderers['fields'] # processing form input diff --git a/browser/form_macros.pt b/browser/form_macros.pt index 6165583..23fa8d6 100644 --- a/browser/form_macros.pt +++ b/browser/form_macros.pt @@ -16,8 +16,7 @@
- - +
@@ -65,7 +64,7 @@
- +
@@ -83,37 +82,6 @@ - - -
- - - - - -
- - -
- -
-
- error -
-
-
-
-
- - diff --git a/configure.zcml b/configure.zcml index 6ffa57d..948ebfb 100644 --- a/configure.zcml +++ b/configure.zcml @@ -401,6 +401,7 @@ + diff --git a/organize/README.txt b/organize/README.txt index dc71710..afae88b 100644 --- a/organize/README.txt +++ b/organize/README.txt @@ -229,9 +229,10 @@ Change Password >>> data = {'oldPassword': u'tiger', ... 'password': u'lion', - ... 'passwordConfirm': u'lion'} + ... 'passwordConfirm': u'lion', + ... 'action': 'update'} - >>> request = TestRequest() + >>> request = TestRequest(form=data) We need a principal for testing the login stuff: @@ -239,10 +240,15 @@ We need a principal for testing the login stuff: >>> principal = InternalPrincipal('scott', 'tiger', 'Scotty') >>> request.setPrincipal(principal) - >>> from loops.organize.browser import PasswordChange - >>> pwcView = PasswordChange(menu, request, testing=True) - >>> pwcView.changePassword(data) + >>> from cybertools.composer.schema.factory import SchemaFactory + >>> from cybertools.composer.schema.field import FieldInstance + >>> component.provideAdapter(SchemaFactory) + >>> component.provideAdapter(FieldInstance) + >>> from loops.organize.browser import PasswordChange + >>> pwcView = PasswordChange(menu, request) + >>> pwcView.update() + False Fin de partie ============= diff --git a/organize/browser.py b/organize/browser.py index ac97af6..87f5020 100644 --- a/organize/browser.py +++ b/organize/browser.py @@ -24,17 +24,18 @@ $Id$ """ from zope import interface, component -from zope.app import zapi from zope.app.authentication.principalfolder import InternalPrincipal from zope.app.form.browser.textwidgets import PasswordWidget as BasePasswordWidget from zope.app.form.interfaces import WidgetInputError -from zope.app.pagetemplate import ViewPageTemplateFile from zope.app.principalannotation import annotations from zope.cachedescriptors.property import Lazy -from zope.formlib.form import Form, FormFields, action +from zope.formlib.form import Form as FormlibForm, FormFields, action from zope.formlib.namedtemplate import NamedTemplate from zope.i18nmessageid import MessageFactory +from cybertools.composer.schema.browser.common import schema_macros +from cybertools.composer.schema.browser.form import Form +from cybertools.composer.schema.schema import FormState, FormError from cybertools.typology.interfaces import IType from loops.browser.concept import ConceptView from loops.browser.node import NodeView @@ -74,23 +75,7 @@ class PasswordWidget(BasePasswordWidget): return value -class OldPasswordWidget(BasePasswordWidget): - - def getInputValue(self): - value = super(OldPasswordWidget, self).getInputValue() - if value: - principal = self.request.principal - if not isinstance(principal, InternalPrincipal): - principal = getInternalPrincipal(principal.id) - if not principal.checkPassword(value): - v = _(u'Your old password was not entered correctly.') - self._error = WidgetInputError( - self.context.__name__, self.label, v) - raise self._error - return value - - -class MemberRegistration(NodeView, Form): +class MemberRegistration(NodeView, FormlibForm): form_fields = FormFields(IMemberRegistration).omit('age') form_fields['password'].custom_widget = PasswordWidget @@ -139,50 +124,64 @@ class MemberRegistration(NodeView, Form): class PasswordChange(NodeView, Form): - form_fields = FormFields(IPasswordChange).select( - 'oldPassword', 'password', 'passwordConfirm') - form_fields['oldPassword'].custom_widget = OldPasswordWidget - form_fields['password'].custom_widget = PasswordWidget - template = loops.browser.util.dataform - label = _(u'Change Password') + interface = IPasswordChange + message = u'Your password has been changed.' - def __init__(self, context, request, testing=False): - super(PasswordChange, self).__init__(context, request) - if not testing: - self.setUpWidgets() + formErrors = dict( + confirm_nomatch=FormError(u'Password and password confirmation do not match.'), + wrong_oldpw=FormError(u'Your old password was not entered correctly.'), + ) + + label = label_submit = u'Change Password' @Lazy def macro(self): - return self.template.macros['content'] + return schema_macros.macros['form'] @Lazy def item(self): return self + @Lazy + def data(self): + data = dict(oldPassword=u'', password=u'', passwordConfirm=u'') + data = {} + return data + def update(self): - # see cybertools.browser.view.GenericView.update() - NodeView.update(self) - Form.update(self) - return True - - @action(_(u'Change Password')) - def handle_change_password_action(self, action, data): - self.changePassword(data) - - def changePassword(self, data=None): - form = data or self.request.form - oldPw = form.get('oldPassword') + form = self.request.form + if not form.get('action'): + return True + formState = self.formState = self.validate(form) + if formState.severity > 0: + return True pw = form.get('password') - if form.get('passwordConfirm') != pw: - raise ValueError(u'Password and password confirmation do not match.') + pwConfirm = form.get('passwordConfirm') + if pw != pwConfirm: + fi = formState.fieldInstances['password'] + fi.setError('confirm_nomatch', self.formErrors) + formState.severity = max(formState.severity, fi.severity) + return True + oldPw = form.get('oldPassword') regMan = IMemberRegistrationManager(self.context.getLoopsRoot()) principal = self.request.principal result = regMan.changePassword(principal, oldPw, pw) if not result: - raise ValueError(u'Your old password was not entered correctly.') - message = _(u'Your password has been changed.') - self.request.response.redirect('%s?message=%s' - % (self.url, message)) - #self.request.response.redirect('%s/logout.html?message=%s' - # % (self.url, message)) + fi = formState.fieldInstances['oldPassword'] + fi.setError('wrong_oldpw', self.formErrors) + formState.severity = max(formState.severity, fi.severity) + return True + url = '%s?messsage=%s' % (self.url, self.message) + self.request.response.redirect(url) + return False + + def validate(self, data): + formState = FormState() + for f in self.schema.fields: + fi = f.getFieldInstance() + value = data.get(f.name) + fi.validate(value, data) + formState.fieldInstances.append(fi) + formState.severity = max(formState.severity, fi.severity) + return formState diff --git a/organize/interfaces.py b/organize/interfaces.py index e7cd780..891b000 100644 --- a/organize/interfaces.py +++ b/organize/interfaces.py @@ -77,12 +77,6 @@ class LoginName(schema.TextLine): mapping=dict(userId=userId))) -class Password(schema.Password): - - def _validate(self, pw): - super(Password, self)._validate(pw) - - class IPerson(IBasePerson): """ Resembles a human being with a name (first and last name), a birth date, and a set of addresses. This interface only @@ -99,7 +93,7 @@ class IPerson(IBasePerson): class IPasswordEntry(Interface): - password = Password(title=_(u'Password'), + password = schema.Password(title=_(u'Password'), description=_(u'Enter password.'), required=True,) passwordConfirm = schema.Password(title=_(u'Confirm password'),