Ticket #9689 (assigned Bug)

Opened 6 years ago

Last modified 4 years ago

@@mail-controlpanel: The ESMTP field should indicate that a value has been saved (now: empty)

Reported by: kleist Owned by: dukebody
Priority: minor Milestone: 4.x
Component: General Version: 4.2
Keywords: Cc:

Description

Plone 4 coredev r30983

After entering an ESMTP password, and saving, this field becomes empty.

It's nice, of course, that the password isn't displayed. However, bullets/asterisks would be preferred.

See also #6916, #7694

Change History

comment:1 Changed 6 years ago by limi

  • Component changed from Unknown to Infrastructure

comment:2 Changed 6 years ago by dukebody

  • Status changed from new to assigned
  • Owner set to dukebody

Interesting!

comment:3 Changed 6 years ago by dukebody

The culprit seems to be zope/app/form/browser/textwidgets.py:

class PasswordWidget(TextWidget):
    """Password Widget"""

    type = 'password'

    def __call__(self):
        displayMaxWidth = self.displayMaxWidth or 0
        if displayMaxWidth > 0:
            return renderElement(self.tag,
                                 type=self.type,
                                 name=self.name,
                                 id=self.name,
                                 value='',
                                 cssClass=self.cssClass,
                                 style=self.style,
                                 size=self.displayWidth,
                                 maxlength=displayMaxWidth,
                                 extra=self.extra)
        else:
            return renderElement(self.tag,
                                 type=self.type,
                                 name=self.name,
                                 id=self.name,
                                 value='',
                                 cssClass=self.cssClass,
                                 style=self.style,
                                 size=self.displayWidth,
                                 extra=self.extra)

Here value="" in both cases. Perhaps this is the intended behaviour.

comment:4 Changed 6 years ago by hannosch

  • Milestone changed from 4.0 to 4.x

This isn't trivial to do, as you don't want to set the actual value back into the form. So you need to set some dummy in there which is displayed as some asterisks. The number of asterisks shouldn't even match the number of characters in the password, but should be something like a constant five.

You then have to check if the supplied value is that magic marker and if it is, treat the value as not being submitted and leave the value as-is. It still needs to be possible to empty the value though and submitting an empty field should ideally delete the value for real.

This is a long standing bug / missing feature in formlib's password field.

comment:5 Changed 6 years ago by dukebody

Hanno, what do you think about:

Index: textwidgets.py
===================================================================
--- textwidgets.py	(revision 109981)
+++ textwidgets.py	(working copy)
@@ -407,36 +407,29 @@
 
     type = 'password'
 
+    def __init__(self):
+        super(PasswordWidget, self).__init__()
+        self.maxlength = self.displayMaxWidth or self.displayWidth
+        self.dummy = '*' * self.maxlength
+
     def __call__(self):
-        displayMaxWidth = self.displayMaxWidth or 0
-        if displayMaxWidth > 0:
-            return renderElement(self.tag,
-                                 type=self.type,
-                                 name=self.name,
-                                 id=self.name,
-                                 value='',
-                                 cssClass=self.cssClass,
-                                 style=self.style,
-                                 size=self.displayWidth,
-                                 maxlength=displayMaxWidth,
-                                 extra=self.extra)
-        else:
-            return renderElement(self.tag,
-                                 type=self.type,
-                                 name=self.name,
-                                 id=self.name,
-                                 value='',
-                                 cssClass=self.cssClass,
-                                 style=self.style,
-                                 size=self.displayWidth,
-                                 extra=self.extra)
+        return renderElement(self.tag,
+                             type=self.type,
+                             name=self.name,
+                             id=self.name,
+                             value=self.dummy,
+                             cssClass=self.cssClass,
+                             style=self.style,
+                             size=self.displayWidth,
+                             maxlength=self.maxlength,
+                             extra=self.extra)
 
     def _toFieldValue(self, input):
         try:
             existing = self.context.get(self.context.context)
         except AttributeError:
             existing = False
-        if (not input) and existing:
+        if (input == self.dummy) and existing:
             return self.context.UNCHANGED_PASSWORD
         return super(PasswordWidget, self)._toFieldValue(input)
 

The zope.app.form.browser.textwidgets.PasswordWidget class would become:

class PasswordWidget(TextWidget):
    """Password Widget"""

    type = 'password'

    def __init__(self):
        super(PasswordWidget, self).__init__()
        self.maxlength = self.displayMaxWidth or self.displayWidth
        self.dummy = '*' * self.maxlength

    def __call__(self):
        return renderElement(self.tag,
                             type=self.type,
                             name=self.name,
                             id=self.name,
                             value=self.dummy,
                             cssClass=self.cssClass,
                             style=self.style,
                             size=self.displayWidth,
                             maxlength=self.maxlength,
                             extra=self.extra)

    def _toFieldValue(self, input):
        try:
            existing = self.context.get(self.context.context)
        except AttributeError:
            existing = False
        if (input == self.dummy) 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')


I've not tested it though.

comment:6 Changed 6 years ago by dukebody

(In [34935]) Branching from trunk r34919 to work on re #9689, password field empty is confusing.

comment:7 Changed 6 years ago by dukebody

(In [34940]) Branching from trunk r34938 to work on re #9689, password field and asterisks in mail controlpanel. Again.

comment:8 Changed 4 years ago by davisagli

  • Component changed from Infrastructure to General

comment:9 Changed 4 years ago by eleddy

  • Version set to 4.2
Note: See TracTickets for help on using tickets.