Ticket #9689 (assigned Bug)
@@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: |
Change History
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.