We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
PasswordResetView::getErrors function never called.
## BUG

<!--

Read https://plone.org/support/bugs first!

Please use the labels at Github, at least one of the types: bug, regression, question, enhancement.

Please include tracebacks, screenshots, code of debugging sessions or code that reproduces the issue if possible.
The best reproductions are in plain Plone installations without addons or at least with minimal needed addons installed.

-->

### What I did:
I am trying to reset the password, using a normal Plone user and I made a PDB inside https://github.com/plone/Products.CMFPlone/blob/master/Products/CMFPlone/browser/login/password_reset.py#L159

URL: {site url}/passwordreset/e3127df738bc41e1976cc36cc9832132?userid=local_manager

### What I expect to happen:
I expected a call `RegistrationTool.testPasswordValidity(password, password2)
` as I have some business logic inside testPasswordValidity but I saw code never coming here

### What actually happened:
As I see inside ''getErrors''  method, there is a call to registration tool testPasswordValidity method but the ''getErrors'' never called.
### What version of Plone/ Addons I am using:
Plone 5.2.5rc



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `Products/CMFPlone/browser/login/password_reset.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 from AccessControl.SecurityManagement import getSecurityManager
3 from email.header import Header
4 from plone.app.layout.navigation.interfaces import INavigationRoot
5 from plone.memoize import view
6 from plone.registry.interfaces import IRegistry
7 from Products.CMFCore.utils import getToolByName
8 from Products.CMFPlone import PloneMessageFactory as _
9 from Products.CMFPlone.interfaces import IPasswordResetToolView
10 from Products.CMFPlone.interfaces.controlpanel import IMailSchema
11 from Products.CMFPlone.PasswordResetTool import ExpiredRequestError
12 from Products.CMFPlone.PasswordResetTool import InvalidRequestError
13 from Products.CMFPlone.utils import safe_unicode
14 from Products.CMFPlone.utils import safeToInt
15 from Products.Five import BrowserView
16 from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
17 from Products.PlonePAS.events import UserInitialLoginInEvent
18 from Products.PlonePAS.events import UserLoggedInEvent
19 from Products.PluggableAuthService.interfaces.plugins import ICredentialsUpdatePlugin  # noqa
20 from Products.statusmessages.interfaces import IStatusMessage
21 from zope.component import getMultiAdapter
22 from zope.component import getUtility
23 from zope.event import notify
24 from zope.i18n import translate
25 from zope.interface import implementer
26 from zope.publisher.interfaces import IPublishTraverse
27 
28 
29 @implementer(IPasswordResetToolView)
30 class PasswordResetToolView(BrowserView):
31 
32     @view.memoize_contextless
33     def portal_state(self):
34         """ return portal_state of plone.app.layout
35         """
36         return getMultiAdapter((self.context, self.request),
37                                name=u"plone_portal_state")
38 
39     def encode_mail_header(self, text):
40         """ Encodes text into correctly encoded email header """
41         return Header(safe_unicode(text), 'utf-8')
42 
43     def encoded_mail_sender(self):
44         """ returns encoded version of Portal name <portal_email> """
45         registry = getUtility(IRegistry)
46         mail_settings = registry.forInterface(IMailSchema, prefix="plone")
47         from_ = mail_settings.email_from_name
48         mail = mail_settings.email_from_address
49         return '"%s" <%s>' % (self.encode_mail_header(from_).encode(), mail)
50 
51     def registered_notify_subject(self):
52         portal_name = self.portal_state().portal_title()
53         return translate(
54             _(
55                 u'mailtemplate_user_account_info',
56                 default=u'User Account Information for ${portal_name}',
57                 mapping={'portal_name': safe_unicode(portal_name)},
58             ),
59             context=self.request,
60         )
61 
62     def mail_password_subject(self):
63         return translate(
64             _(
65                 u'mailtemplate_subject_resetpasswordrequest',
66                 default=u'Password reset request',
67             ),
68             context=self.request,
69         )
70 
71     def construct_url(self, randomstring):
72         return '%s/passwordreset/%s' % (
73             self.portal_state().navigation_root_url(), randomstring)
74 
75     def expiration_timeout(self):
76         pw_tool = getToolByName(self.context, 'portal_password_reset')
77         timeout = int(pw_tool.getExpirationTimeout() or 0)
78         return timeout * 24  # timeout is in days, but templates want in hours.
79 
80 
81 @implementer(IPublishTraverse)
82 class PasswordResetView(BrowserView):
83     """ """
84 
85     invalid = ViewPageTemplateFile('templates/pwreset_invalid.pt')
86     expired = ViewPageTemplateFile('templates/pwreset_expired.pt')
87     finish = ViewPageTemplateFile('templates/pwreset_finish.pt')
88     form = ViewPageTemplateFile('templates/pwreset_form.pt')
89     subpath = None
90 
91     def _auto_login(self, userid, password):
92         aclu = getToolByName(self.context, 'acl_users')
93         for name, plugin in aclu.plugins.listPlugins(ICredentialsUpdatePlugin):
94             plugin.updateCredentials(
95                 self.request,
96                 self.request.response,
97                 userid,
98                 password
99             )
100         user = getSecurityManager().getUser()
101         login_time = user.getProperty('login_time', None)
102         if login_time is None:
103             notify(UserInitialLoginInEvent(user))
104         else:
105             notify(UserLoggedInEvent(user))
106 
107         IStatusMessage(self.request).addStatusMessage(
108             _(
109                 'password_reset_successful',
110                 default='Password reset successful, '
111                         'you are logged in now!',
112             ),
113             'info',
114         )
115         url = INavigationRoot(self.context).absolute_url()
116         self.request.response.redirect(url)
117         return
118 
119     def _reset_password(self, pw_tool, randomstring):
120         userid = self.request.form.get('userid')
121         password = self.request.form.get('password')
122         try:
123             pw_tool.resetPassword(userid, randomstring, password)
124         except ExpiredRequestError:
125             return self.expired()
126         except InvalidRequestError:
127             return self.invalid()
128         except RuntimeError:
129             return self.invalid()
130         registry = getUtility(IRegistry)
131         if registry.get('plone.autologin_after_password_reset', False):
132             return self._auto_login(userid, password)
133         return self.finish()
134 
135     def __call__(self):
136         if self.subpath:
137             # Try traverse subpath first:
138             randomstring = self.subpath[0]
139         else:
140             randomstring = self.request.get('key', None)
141 
142         pw_tool = getToolByName(self.context, 'portal_password_reset')
143         if self.request.method == 'POST':
144             return self._reset_password(pw_tool, randomstring)
145         try:
146             pw_tool.verifyKey(randomstring)
147         except InvalidRequestError:
148             return self.invalid()
149         except ExpiredRequestError:
150             return self.expired()
151         return self.form()
152 
153     def publishTraverse(self, request, name):
154         if self.subpath is None:
155             self.subpath = []
156         self.subpath.append(name)
157         return self
158 
159     def getErrors(self):
160         if self.request.method != 'POST':
161             return
162         password = self.request.form.get('password')
163         password2 = self.request.form.get('password2')
164         userid = self.request.form.get('userid')
165         reg_tool = getToolByName(self.context, 'portal_registration')
166         pw_fail = reg_tool.testPasswordValidity(password, password2)
167         state = {}
168         if pw_fail:
169             state['password'] = pw_fail
170 
171         # Determine if we're checking userids or not
172         pw_tool = getToolByName(self.context, 'portal_password_reset')
173         if not pw_tool.checkUser():
174             return state
175 
176         if not userid:
177             state['userid'] = _(
178                 'This field is required, please provide some information.',
179             )
180         if state:
181             state['status'] = 'failure'
182             state['portal_status_message'] = _(
183                 'Please correct the indicated errors.',
184             )
185         return state
186 
187     def login_url(self):
188         portal_state = getMultiAdapter((self.context, self.request),
189                                        name=u"plone_portal_state")
190         return '{0}/login?__ac_name={1}'.format(
191             portal_state.navigation_root_url(),
192             self.request.form.get('userid', ''))
193 
194     def expiration_timeout(self):
195         pw_tool = getToolByName(self.context, 'portal_password_reset')
196         timeout = int(pw_tool.getExpirationTimeout() or 0)
197         return timeout * 24  # timeout is in days, but templates want in hours.
198 
199 
200 class ExplainPWResetToolView(BrowserView):
201     """ """
202 
203     def timeout_days(self):
204         return self.context.getExpirationTimeout()
205 
206     def user_check(self):
207         return self.context._user_check and 'checked' or None
208 
209     @property
210     def stats(self):
211         """Return a dictionary like so:
212             {"open":3, "expired":0}
213         about the number of open and expired reset requests.
214         """
215         # count expired reset requests by creating a list of it
216         bad = len([1 for expiry in self.context._requests.values()
217                    if self.context.expired(expiry)])
218         # open reset requests are all requests without the expired ones
219         good = len(self.context._requests) - bad
220         return {"open": good, "expired": bad}
221 
222     def __call__(self):
223         if self.request.method == 'POST':
224             timeout_days = safeToInt(self.request.get('timeout_days'), 7)
225             self.context.setExpirationTimeout(timeout_days)
226             self.context._user_check = bool(
227                 self.request.get('user_check', False),
228             )
229         return self.index()
230
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/Products/CMFPlone/browser/login/password_reset.py b/Products/CMFPlone/browser/login/password_reset.py
--- a/Products/CMFPlone/browser/login/password_reset.py
+++ b/Products/CMFPlone/browser/login/password_reset.py
@@ -117,6 +117,9 @@
         return
 
     def _reset_password(self, pw_tool, randomstring):
+        state = self.getErrors()
+        if state:
+            return self.form()
         userid = self.request.form.get('userid')
         password = self.request.form.get('password')
         try:

{"golden_diff": "diff --git a/Products/CMFPlone/browser/login/password_reset.py b/Products/CMFPlone/browser/login/password_reset.py\n--- a/Products/CMFPlone/browser/login/password_reset.py\n+++ b/Products/CMFPlone/browser/login/password_reset.py\n@@ -117,6 +117,9 @@\n         return\n \n     def _reset_password(self, pw_tool, randomstring):\n+        state = self.getErrors()\n+        if state:\n+            return self.form()\n         userid = self.request.form.get('userid')\n         password = self.request.form.get('password')\n         try:\n", "issue": "PasswordResetView::getErrors function never called.\n## BUG\r\n\r\n<!--\r\n\r\nRead https://plone.org/support/bugs first!\r\n\r\nPlease use the labels at Github, at least one of the types: bug, regression, question, enhancement.\r\n\r\nPlease include tracebacks, screenshots, code of debugging sessions or code that reproduces the issue if possible.\r\nThe best reproductions are in plain Plone installations without addons or at least with minimal needed addons installed.\r\n\r\n-->\r\n\r\n### What I did:\r\nI am trying to reset the password, using a normal Plone user and I made a PDB inside https://github.com/plone/Products.CMFPlone/blob/master/Products/CMFPlone/browser/login/password_reset.py#L159\r\n\r\nURL: {site url}/passwordreset/e3127df738bc41e1976cc36cc9832132?userid=local_manager\r\n\r\n### What I expect to happen:\r\nI expected a call `RegistrationTool.testPasswordValidity(password, password2)\r\n` as I have some business logic inside testPasswordValidity but I saw code never coming here\r\n\r\n### What actually happened:\r\nAs I see inside ''getErrors''  method, there is a call to registration tool testPasswordValidity method but the ''getErrors'' never called.\r\n### What version of Plone/ Addons I am using:\r\nPlone 5.2.5rc\r\n\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nfrom AccessControl.SecurityManagement import getSecurityManager\nfrom email.header import Header\nfrom plone.app.layout.navigation.interfaces import INavigationRoot\nfrom plone.memoize import view\nfrom plone.registry.interfaces import IRegistry\nfrom Products.CMFCore.utils import getToolByName\nfrom Products.CMFPlone import PloneMessageFactory as _\nfrom Products.CMFPlone.interfaces import IPasswordResetToolView\nfrom Products.CMFPlone.interfaces.controlpanel import IMailSchema\nfrom Products.CMFPlone.PasswordResetTool import ExpiredRequestError\nfrom Products.CMFPlone.PasswordResetTool import InvalidRequestError\nfrom Products.CMFPlone.utils import safe_unicode\nfrom Products.CMFPlone.utils import safeToInt\nfrom Products.Five import BrowserView\nfrom Products.Five.browser.pagetemplatefile import ViewPageTemplateFile\nfrom Products.PlonePAS.events import UserInitialLoginInEvent\nfrom Products.PlonePAS.events import UserLoggedInEvent\nfrom Products.PluggableAuthService.interfaces.plugins import ICredentialsUpdatePlugin  # noqa\nfrom Products.statusmessages.interfaces import IStatusMessage\nfrom zope.component import getMultiAdapter\nfrom zope.component import getUtility\nfrom zope.event import notify\nfrom zope.i18n import translate\nfrom zope.interface import implementer\nfrom zope.publisher.interfaces import IPublishTraverse\n\n\n@implementer(IPasswordResetToolView)\nclass PasswordResetToolView(BrowserView):\n\n    @view.memoize_contextless\n    def portal_state(self):\n        \"\"\" return portal_state of plone.app.layout\n        \"\"\"\n        return getMultiAdapter((self.context, self.request),\n                               name=u\"plone_portal_state\")\n\n    def encode_mail_header(self, text):\n        \"\"\" Encodes text into correctly encoded email header \"\"\"\n        return Header(safe_unicode(text), 'utf-8')\n\n    def encoded_mail_sender(self):\n        \"\"\" returns encoded version of Portal name <portal_email> \"\"\"\n        registry = getUtility(IRegistry)\n        mail_settings = registry.forInterface(IMailSchema, prefix=\"plone\")\n        from_ = mail_settings.email_from_name\n        mail = mail_settings.email_from_address\n        return '\"%s\" <%s>' % (self.encode_mail_header(from_).encode(), mail)\n\n    def registered_notify_subject(self):\n        portal_name = self.portal_state().portal_title()\n        return translate(\n            _(\n                u'mailtemplate_user_account_info',\n                default=u'User Account Information for ${portal_name}',\n                mapping={'portal_name': safe_unicode(portal_name)},\n            ),\n            context=self.request,\n        )\n\n    def mail_password_subject(self):\n        return translate(\n            _(\n                u'mailtemplate_subject_resetpasswordrequest',\n                default=u'Password reset request',\n            ),\n            context=self.request,\n        )\n\n    def construct_url(self, randomstring):\n        return '%s/passwordreset/%s' % (\n            self.portal_state().navigation_root_url(), randomstring)\n\n    def expiration_timeout(self):\n        pw_tool = getToolByName(self.context, 'portal_password_reset')\n        timeout = int(pw_tool.getExpirationTimeout() or 0)\n        return timeout * 24  # timeout is in days, but templates want in hours.\n\n\n@implementer(IPublishTraverse)\nclass PasswordResetView(BrowserView):\n    \"\"\" \"\"\"\n\n    invalid = ViewPageTemplateFile('templates/pwreset_invalid.pt')\n    expired = ViewPageTemplateFile('templates/pwreset_expired.pt')\n    finish = ViewPageTemplateFile('templates/pwreset_finish.pt')\n    form = ViewPageTemplateFile('templates/pwreset_form.pt')\n    subpath = None\n\n    def _auto_login(self, userid, password):\n        aclu = getToolByName(self.context, 'acl_users')\n        for name, plugin in aclu.plugins.listPlugins(ICredentialsUpdatePlugin):\n            plugin.updateCredentials(\n                self.request,\n                self.request.response,\n                userid,\n                password\n            )\n        user = getSecurityManager().getUser()\n        login_time = user.getProperty('login_time', None)\n        if login_time is None:\n            notify(UserInitialLoginInEvent(user))\n        else:\n            notify(UserLoggedInEvent(user))\n\n        IStatusMessage(self.request).addStatusMessage(\n            _(\n                'password_reset_successful',\n                default='Password reset successful, '\n                        'you are logged in now!',\n            ),\n            'info',\n        )\n        url = INavigationRoot(self.context).absolute_url()\n        self.request.response.redirect(url)\n        return\n\n    def _reset_password(self, pw_tool, randomstring):\n        userid = self.request.form.get('userid')\n        password = self.request.form.get('password')\n        try:\n            pw_tool.resetPassword(userid, randomstring, password)\n        except ExpiredRequestError:\n            return self.expired()\n        except InvalidRequestError:\n            return self.invalid()\n        except RuntimeError:\n            return self.invalid()\n        registry = getUtility(IRegistry)\n        if registry.get('plone.autologin_after_password_reset', False):\n            return self._auto_login(userid, password)\n        return self.finish()\n\n    def __call__(self):\n        if self.subpath:\n            # Try traverse subpath first:\n            randomstring = self.subpath[0]\n        else:\n            randomstring = self.request.get('key', None)\n\n        pw_tool = getToolByName(self.context, 'portal_password_reset')\n        if self.request.method == 'POST':\n            return self._reset_password(pw_tool, randomstring)\n        try:\n            pw_tool.verifyKey(randomstring)\n        except InvalidRequestError:\n            return self.invalid()\n        except ExpiredRequestError:\n            return self.expired()\n        return self.form()\n\n    def publishTraverse(self, request, name):\n        if self.subpath is None:\n            self.subpath = []\n        self.subpath.append(name)\n        return self\n\n    def getErrors(self):\n        if self.request.method != 'POST':\n            return\n        password = self.request.form.get('password')\n        password2 = self.request.form.get('password2')\n        userid = self.request.form.get('userid')\n        reg_tool = getToolByName(self.context, 'portal_registration')\n        pw_fail = reg_tool.testPasswordValidity(password, password2)\n        state = {}\n        if pw_fail:\n            state['password'] = pw_fail\n\n        # Determine if we're checking userids or not\n        pw_tool = getToolByName(self.context, 'portal_password_reset')\n        if not pw_tool.checkUser():\n            return state\n\n        if not userid:\n            state['userid'] = _(\n                'This field is required, please provide some information.',\n            )\n        if state:\n            state['status'] = 'failure'\n            state['portal_status_message'] = _(\n                'Please correct the indicated errors.',\n            )\n        return state\n\n    def login_url(self):\n        portal_state = getMultiAdapter((self.context, self.request),\n                                       name=u\"plone_portal_state\")\n        return '{0}/login?__ac_name={1}'.format(\n            portal_state.navigation_root_url(),\n            self.request.form.get('userid', ''))\n\n    def expiration_timeout(self):\n        pw_tool = getToolByName(self.context, 'portal_password_reset')\n        timeout = int(pw_tool.getExpirationTimeout() or 0)\n        return timeout * 24  # timeout is in days, but templates want in hours.\n\n\nclass ExplainPWResetToolView(BrowserView):\n    \"\"\" \"\"\"\n\n    def timeout_days(self):\n        return self.context.getExpirationTimeout()\n\n    def user_check(self):\n        return self.context._user_check and 'checked' or None\n\n    @property\n    def stats(self):\n        \"\"\"Return a dictionary like so:\n            {\"open\":3, \"expired\":0}\n        about the number of open and expired reset requests.\n        \"\"\"\n        # count expired reset requests by creating a list of it\n        bad = len([1 for expiry in self.context._requests.values()\n                   if self.context.expired(expiry)])\n        # open reset requests are all requests without the expired ones\n        good = len(self.context._requests) - bad\n        return {\"open\": good, \"expired\": bad}\n\n    def __call__(self):\n        if self.request.method == 'POST':\n            timeout_days = safeToInt(self.request.get('timeout_days'), 7)\n            self.context.setExpirationTimeout(timeout_days)\n            self.context._user_check = bool(\n                self.request.get('user_check', False),\n            )\n        return self.index()\n", "path": "Products/CMFPlone/browser/login/password_reset.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nfrom AccessControl.SecurityManagement import getSecurityManager\nfrom email.header import Header\nfrom plone.app.layout.navigation.interfaces import INavigationRoot\nfrom plone.memoize import view\nfrom plone.registry.interfaces import IRegistry\nfrom Products.CMFCore.utils import getToolByName\nfrom Products.CMFPlone import PloneMessageFactory as _\nfrom Products.CMFPlone.interfaces import IPasswordResetToolView\nfrom Products.CMFPlone.interfaces.controlpanel import IMailSchema\nfrom Products.CMFPlone.PasswordResetTool import ExpiredRequestError\nfrom Products.CMFPlone.PasswordResetTool import InvalidRequestError\nfrom Products.CMFPlone.utils import safe_unicode\nfrom Products.CMFPlone.utils import safeToInt\nfrom Products.Five import BrowserView\nfrom Products.Five.browser.pagetemplatefile import ViewPageTemplateFile\nfrom Products.PlonePAS.events import UserInitialLoginInEvent\nfrom Products.PlonePAS.events import UserLoggedInEvent\nfrom Products.PluggableAuthService.interfaces.plugins import ICredentialsUpdatePlugin  # noqa\nfrom Products.statusmessages.interfaces import IStatusMessage\nfrom zope.component import getMultiAdapter\nfrom zope.component import getUtility\nfrom zope.event import notify\nfrom zope.i18n import translate\nfrom zope.interface import implementer\nfrom zope.publisher.interfaces import IPublishTraverse\n\n\n@implementer(IPasswordResetToolView)\nclass PasswordResetToolView(BrowserView):\n\n    @view.memoize_contextless\n    def portal_state(self):\n        \"\"\" return portal_state of plone.app.layout\n        \"\"\"\n        return getMultiAdapter((self.context, self.request),\n                               name=u\"plone_portal_state\")\n\n    def encode_mail_header(self, text):\n        \"\"\" Encodes text into correctly encoded email header \"\"\"\n        return Header(safe_unicode(text), 'utf-8')\n\n    def encoded_mail_sender(self):\n        \"\"\" returns encoded version of Portal name <portal_email> \"\"\"\n        registry = getUtility(IRegistry)\n        mail_settings = registry.forInterface(IMailSchema, prefix=\"plone\")\n        from_ = mail_settings.email_from_name\n        mail = mail_settings.email_from_address\n        return '\"%s\" <%s>' % (self.encode_mail_header(from_).encode(), mail)\n\n    def registered_notify_subject(self):\n        portal_name = self.portal_state().portal_title()\n        return translate(\n            _(\n                u'mailtemplate_user_account_info',\n                default=u'User Account Information for ${portal_name}',\n                mapping={'portal_name': safe_unicode(portal_name)},\n            ),\n            context=self.request,\n        )\n\n    def mail_password_subject(self):\n        return translate(\n            _(\n                u'mailtemplate_subject_resetpasswordrequest',\n                default=u'Password reset request',\n            ),\n            context=self.request,\n        )\n\n    def construct_url(self, randomstring):\n        return '%s/passwordreset/%s' % (\n            self.portal_state().navigation_root_url(), randomstring)\n\n    def expiration_timeout(self):\n        pw_tool = getToolByName(self.context, 'portal_password_reset')\n        timeout = int(pw_tool.getExpirationTimeout() or 0)\n        return timeout * 24  # timeout is in days, but templates want in hours.\n\n\n@implementer(IPublishTraverse)\nclass PasswordResetView(BrowserView):\n    \"\"\" \"\"\"\n\n    invalid = ViewPageTemplateFile('templates/pwreset_invalid.pt')\n    expired = ViewPageTemplateFile('templates/pwreset_expired.pt')\n    finish = ViewPageTemplateFile('templates/pwreset_finish.pt')\n    form = ViewPageTemplateFile('templates/pwreset_form.pt')\n    subpath = None\n\n    def _auto_login(self, userid, password):\n        aclu = getToolByName(self.context, 'acl_users')\n        for name, plugin in aclu.plugins.listPlugins(ICredentialsUpdatePlugin):\n            plugin.updateCredentials(\n                self.request,\n                self.request.response,\n                userid,\n                password\n            )\n        user = getSecurityManager().getUser()\n        login_time = user.getProperty('login_time', None)\n        if login_time is None:\n            notify(UserInitialLoginInEvent(user))\n        else:\n            notify(UserLoggedInEvent(user))\n\n        IStatusMessage(self.request).addStatusMessage(\n            _(\n                'password_reset_successful',\n                default='Password reset successful, '\n                        'you are logged in now!',\n            ),\n            'info',\n        )\n        url = INavigationRoot(self.context).absolute_url()\n        self.request.response.redirect(url)\n        return\n\n    def _reset_password(self, pw_tool, randomstring):\n        state = self.getErrors()\n        if state:\n            return self.form()\n        userid = self.request.form.get('userid')\n        password = self.request.form.get('password')\n        try:\n            pw_tool.resetPassword(userid, randomstring, password)\n        except ExpiredRequestError:\n            return self.expired()\n        except InvalidRequestError:\n            return self.invalid()\n        except RuntimeError:\n            return self.invalid()\n        registry = getUtility(IRegistry)\n        if registry.get('plone.autologin_after_password_reset', False):\n            return self._auto_login(userid, password)\n        return self.finish()\n\n    def __call__(self):\n        if self.subpath:\n            # Try traverse subpath first:\n            randomstring = self.subpath[0]\n        else:\n            randomstring = self.request.get('key', None)\n\n        pw_tool = getToolByName(self.context, 'portal_password_reset')\n        if self.request.method == 'POST':\n            return self._reset_password(pw_tool, randomstring)\n        try:\n            pw_tool.verifyKey(randomstring)\n        except InvalidRequestError:\n            return self.invalid()\n        except ExpiredRequestError:\n            return self.expired()\n        return self.form()\n\n    def publishTraverse(self, request, name):\n        if self.subpath is None:\n            self.subpath = []\n        self.subpath.append(name)\n        return self\n\n    def getErrors(self):\n        if self.request.method != 'POST':\n            return\n        password = self.request.form.get('password')\n        password2 = self.request.form.get('password2')\n        userid = self.request.form.get('userid')\n        reg_tool = getToolByName(self.context, 'portal_registration')\n        pw_fail = reg_tool.testPasswordValidity(password, password2)\n        state = {}\n        if pw_fail:\n            state['password'] = pw_fail\n\n        # Determine if we're checking userids or not\n        pw_tool = getToolByName(self.context, 'portal_password_reset')\n        if not pw_tool.checkUser():\n            return state\n\n        if not userid:\n            state['userid'] = _(\n                'This field is required, please provide some information.',\n            )\n        if state:\n            state['status'] = 'failure'\n            state['portal_status_message'] = _(\n                'Please correct the indicated errors.',\n            )\n        return state\n\n    def login_url(self):\n        portal_state = getMultiAdapter((self.context, self.request),\n                                       name=u\"plone_portal_state\")\n        return '{0}/login?__ac_name={1}'.format(\n            portal_state.navigation_root_url(),\n            self.request.form.get('userid', ''))\n\n    def expiration_timeout(self):\n        pw_tool = getToolByName(self.context, 'portal_password_reset')\n        timeout = int(pw_tool.getExpirationTimeout() or 0)\n        return timeout * 24  # timeout is in days, but templates want in hours.\n\n\nclass ExplainPWResetToolView(BrowserView):\n    \"\"\" \"\"\"\n\n    def timeout_days(self):\n        return self.context.getExpirationTimeout()\n\n    def user_check(self):\n        return self.context._user_check and 'checked' or None\n\n    @property\n    def stats(self):\n        \"\"\"Return a dictionary like so:\n            {\"open\":3, \"expired\":0}\n        about the number of open and expired reset requests.\n        \"\"\"\n        # count expired reset requests by creating a list of it\n        bad = len([1 for expiry in self.context._requests.values()\n                   if self.context.expired(expiry)])\n        # open reset requests are all requests without the expired ones\n        good = len(self.context._requests) - bad\n        return {\"open\": good, \"expired\": bad}\n\n    def __call__(self):\n        if self.request.method == 'POST':\n            timeout_days = safeToInt(self.request.get('timeout_days'), 7)\n            self.context.setExpirationTimeout(timeout_days)\n            self.context._user_check = bool(\n                self.request.get('user_check', False),\n            )\n        return self.index()\n", "path": "Products/CMFPlone/browser/login/password_reset.py"}]}