[Zope3-checkins] SVN: Zope3/trunk/ - Fixed password widget to allow users to not change

Christian Theune ct at gocept.com
Thu Dec 7 11:42:03 EST 2006


Log message for revision 71484:
   - Fixed password widget to allow users to not change
     their password when being confronted with a password field.
  
  

Changed:
  U   Zope3/trunk/doc/CHANGES.txt
  U   Zope3/trunk/src/zope/app/form/browser/tests/test_textwidget.py
  U   Zope3/trunk/src/zope/app/form/browser/textwidgets.py
  U   Zope3/trunk/src/zope/schema/_bootstrapfields.py
  U   Zope3/trunk/src/zope/schema/tests/test_strfield.py

-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt	2006-12-07 16:12:16 UTC (rev 71483)
+++ Zope3/trunk/doc/CHANGES.txt	2006-12-07 16:42:02 UTC (rev 71484)
@@ -149,6 +149,9 @@
 
     Bug fixes
 
+      - Fixed behaviour of PasswordWidget to allow users not changing their
+        password when a password already exists.
+
       - Fileresources now also set the Cache-control headers on 304
         responses. This speeds up page loads a lot on pages with many
         resources.

Modified: Zope3/trunk/src/zope/app/form/browser/tests/test_textwidget.py
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/tests/test_textwidget.py	2006-12-07 16:12:16 UTC (rev 71483)
+++ Zope3/trunk/src/zope/app/form/browser/tests/test_textwidget.py	2006-12-07 16:42:02 UTC (rev 71484)
@@ -22,6 +22,7 @@
 from zope.schema import TextLine
 from zope.publisher.browser import TestRequest
 
+from zope.schema import Password
 from zope.app.form.interfaces import IInputWidget
 
 from zope.app.form.browser import TextWidget
@@ -316,6 +317,7 @@
 class PasswordDisplayWidgetTest(BrowserWidgetTest):
 
     _WidgetFactory = PasswordWidget
+    _FieldFactory = Password
 
     # It uses the default DisplayWidget
     def testRender(self):
@@ -325,6 +327,16 @@
                       'value=""', 'size="20"')
         self.verifyResult(self._widget(), check_list)
 
+    def testUnchangedPassword(self):
+        # The password hasn't been set yet, so an empty string
+        # is regarded as an empty field.
+        self.assertEquals(None, self._widget._toFieldValue(''))
+        # Now the password has been filled in, so the empty string
+        # is regarded as the special value for UNCHANGED_PASSWORD.
+        self._widget.context.context.foo = u'existing password'
+        self.assertEquals(self._widget.context.UNCHANGED_PASSWORD, 
+                          self._widget._toFieldValue(''))
+
 class FileDisplayWidgetTest(BrowserWidgetTest):
 
     _WidgetFactory = FileWidget

Modified: Zope3/trunk/src/zope/app/form/browser/textwidgets.py
===================================================================
--- Zope3/trunk/src/zope/app/form/browser/textwidgets.py	2006-12-07 16:12:16 UTC (rev 71483)
+++ Zope3/trunk/src/zope/app/form/browser/textwidgets.py	2006-12-07 16:42:02 UTC (rev 71484)
@@ -388,10 +388,20 @@
                                  size=self.displayWidth,
                                  extra=self.extra)
 
+    def _toFieldValue(self, input):
+        try:
+            existing = self.context.get(self.context.context)
+        except AttributeError:
+            existing = False
+        if (not input) and existing:
+            return self.context.UNCHANGED_PASSWORD
+        return super(PasswordWidget, self)._toFieldValue(input)
+
     def hidden(self):
         raise NotImplementedError(
             'Cannot get a hidden tag for a password field')
 
+
 class FileWidget(TextWidget):
     """File Widget"""
 

Modified: Zope3/trunk/src/zope/schema/_bootstrapfields.py
===================================================================
--- Zope3/trunk/src/zope/schema/_bootstrapfields.py	2006-12-07 16:12:16 UTC (rev 71483)
+++ Zope3/trunk/src/zope/schema/_bootstrapfields.py	2006-12-07 16:42:02 UTC (rev 71484)
@@ -300,9 +300,37 @@
     def constraint(self, value):
         return '\n' not in value and '\r' not in value
 
+
 class Password(TextLine):
     """A text field containing a text used as a password."""
 
+    UNCHANGED_PASSWORD = object()
+
+    def set(self, context, value):
+        """Update the password.
+
+        We use a special marker value that a widget can use
+        to tell us that the password didn't change. This is
+        needed to support edit forms that don't display the
+        existing password and want to work together with
+        encryption.
+
+        """
+        if value is self.UNCHANGED_PASSWORD:
+            return
+        super(Password, self).set(context, value)
+
+    def validate(self, value):
+        try:
+            existing = bool(self.get(self.context))
+        except AttributeError:
+            existing = False
+        if value is self.UNCHANGED_PASSWORD and existing:
+            # Allow the UNCHANGED_PASSWORD value, if a password is set already
+            return
+        return super(Password, self).validate(value)
+
+
 class Bool(Field):
     """A field representing a Bool."""
     _type = type(True)

Modified: Zope3/trunk/src/zope/schema/tests/test_strfield.py
===================================================================
--- Zope3/trunk/src/zope/schema/tests/test_strfield.py	2006-12-07 16:12:16 UTC (rev 71483)
+++ Zope3/trunk/src/zope/schema/tests/test_strfield.py	2006-12-07 16:42:02 UTC (rev 71484)
@@ -16,8 +16,8 @@
 $Id$
 """
 from unittest import TestSuite, main, makeSuite
-from zope.schema import Bytes, BytesLine, Text, TextLine
-from zope.schema.interfaces import ValidationError
+from zope.schema import Bytes, BytesLine, Text, TextLine, Password
+from zope.schema.interfaces import ValidationError, WrongType
 from zope.schema.interfaces import RequiredMissing, InvalidValue
 from zope.schema.interfaces import TooShort, TooLong, ConstraintNotSatisfied
 from zope.schema.tests.test_field import FieldTestBase
@@ -119,6 +119,33 @@
                                     field.validate,
                                     self._convert('hello\nworld'))
 
+class PasswordTest(SingleLine, TextTest):
+    _Field_Factory = Password
+
+    def test_existingValue(self):
+        class Dummy(object):
+            password = None
+        dummy = Dummy()
+
+        field = self._Field_Factory(title=u'Str field', description=u'',
+                                    readonly=False, required=True, __name__='password')
+        field = field.bind(dummy)
+
+        # Using UNCHANGED_PASSWORD is not allowed if no password was set yet
+        self.assertRaises(WrongType, field.validate, field.UNCHANGED_PASSWORD)
+
+        dummy.password = 'asdf'
+        field.validate(field.UNCHANGED_PASSWORD)
+
+        # Using a normal value, the field gets updated
+        field.set(dummy, u'test')
+        self.assertEquals(u'test', dummy.password)
+
+        # Using UNCHANGED_PASSWORD the field is not updated.
+        field.set(dummy, field.UNCHANGED_PASSWORD)
+        self.assertEquals(u'test', dummy.password)
+
+
 class LineTest(SingleLine, BytesTest):
     _Field_Factory = BytesLine
 
@@ -132,6 +159,7 @@
         makeSuite(TextTest),
         makeSuite(LineTest),
         makeSuite(TextLineTest),
+        makeSuite(PasswordTest),
         ))
 
 if __name__ == '__main__':



More information about the Zope3-Checkins mailing list