We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Login user after password reset notify events with Anonymous User
## BUG/PROBLEM REPORT

The option **Login user after password reset** allows a user that just performed a password reset to automatically log in after the .process is complete.

One of the two events (**UserLoggedInEvent**, **UserInitialLoginInEvent**) is triggered by this process, but with the Anonymous User instead of the user that just performed the password request.

### What I did:

- Newly created Plone site (no addons)
- **Login user after password reset** selected on */@@security-controlpanel*
- Create a new user
- Request a reset user password
- Follow the generated link

### What I expect to happen:

**UserLoggedInEvent** or **UserInitialLoginInEvent** should be triggered with the newly logged in user.

### What actually happened:

**UserLoggedInEvent** and **UserInitialLoginInEvent** are triggrered with **<SpecialUser 'Anonymous User'>**.

### What version of Plone/ Addons I am using:

* Plone 5.2
* No addons


--- 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         state = self.getErrors()
121         if state:
122             return self.form()
123         userid = self.request.form.get('userid')
124         password = self.request.form.get('password')
125         try:
126             pw_tool.resetPassword(userid, randomstring, password)
127         except ExpiredRequestError:
128             return self.expired()
129         except InvalidRequestError:
130             return self.invalid()
131         except RuntimeError:
132             return self.invalid()
133         registry = getUtility(IRegistry)
134         if registry.get('plone.autologin_after_password_reset', False):
135             return self._auto_login(userid, password)
136         return self.finish()
137 
138     def __call__(self):
139         if self.subpath:
140             # Try traverse subpath first:
141             randomstring = self.subpath[0]
142         else:
143             randomstring = self.request.get('key', None)
144 
145         pw_tool = getToolByName(self.context, 'portal_password_reset')
146         if self.request.method == 'POST':
147             return self._reset_password(pw_tool, randomstring)
148         try:
149             pw_tool.verifyKey(randomstring)
150         except InvalidRequestError:
151             return self.invalid()
152         except ExpiredRequestError:
153             return self.expired()
154         return self.form()
155 
156     def publishTraverse(self, request, name):
157         if self.subpath is None:
158             self.subpath = []
159         self.subpath.append(name)
160         return self
161 
162     def getErrors(self):
163         if self.request.method != 'POST':
164             return
165         password = self.request.form.get('password')
166         password2 = self.request.form.get('password2')
167         userid = self.request.form.get('userid')
168         reg_tool = getToolByName(self.context, 'portal_registration')
169         pw_fail = reg_tool.testPasswordValidity(password, password2)
170         state = {}
171         if pw_fail:
172             state['password'] = pw_fail
173 
174         # Determine if we're checking userids or not
175         pw_tool = getToolByName(self.context, 'portal_password_reset')
176         if not pw_tool.checkUser():
177             return state
178 
179         if not userid:
180             state['userid'] = _(
181                 'This field is required, please provide some information.',
182             )
183         if state:
184             state['status'] = 'failure'
185             state['portal_status_message'] = _(
186                 'Please correct the indicated errors.',
187             )
188         return state
189 
190     def login_url(self):
191         portal_state = getMultiAdapter((self.context, self.request),
192                                        name=u"plone_portal_state")
193         return '{0}/login?__ac_name={1}'.format(
194             portal_state.navigation_root_url(),
195             self.request.form.get('userid', ''))
196 
197     def expiration_timeout(self):
198         pw_tool = getToolByName(self.context, 'portal_password_reset')
199         timeout = int(pw_tool.getExpirationTimeout() or 0)
200         return timeout * 24  # timeout is in days, but templates want in hours.
201 
202 
203 class ExplainPWResetToolView(BrowserView):
204     """ """
205 
206     def timeout_days(self):
207         return self.context.getExpirationTimeout()
208 
209     def user_check(self):
210         return self.context._user_check and 'checked' or None
211 
212     @property
213     def stats(self):
214         """Return a dictionary like so:
215             {"open":3, "expired":0}
216         about the number of open and expired reset requests.
217         """
218         # count expired reset requests by creating a list of it
219         bad = len([1 for expiry in self.context._requests.values()
220                    if self.context.expired(expiry)])
221         # open reset requests are all requests without the expired ones
222         good = len(self.context._requests) - bad
223         return {"open": good, "expired": bad}
224 
225     def __call__(self):
226         if self.request.method == 'POST':
227             timeout_days = safeToInt(self.request.get('timeout_days'), 7)
228             self.context.setExpirationTimeout(timeout_days)
229             self.context._user_check = bool(
230                 self.request.get('user_check', False),
231             )
232         return self.index()
233
```
--- 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
@@ -10,6 +10,7 @@
 from Products.CMFPlone.interfaces.controlpanel import IMailSchema
 from Products.CMFPlone.PasswordResetTool import ExpiredRequestError
 from Products.CMFPlone.PasswordResetTool import InvalidRequestError
+from Products.CMFPlone.RegistrationTool import get_member_by_login_name
 from Products.CMFPlone.utils import safe_unicode
 from Products.CMFPlone.utils import safeToInt
 from Products.Five import BrowserView
@@ -89,7 +90,8 @@
     subpath = None
 
     def _auto_login(self, userid, password):
-        aclu = getToolByName(self.context, 'acl_users')
+        context = self.context
+        aclu = getToolByName(context, 'acl_users')
         for name, plugin in aclu.plugins.listPlugins(ICredentialsUpdatePlugin):
             plugin.updateCredentials(
                 self.request,
@@ -97,7 +99,16 @@
                 userid,
                 password
             )
-        user = getSecurityManager().getUser()
+
+        member = get_member_by_login_name(context, userid, False)
+
+        if member:
+            user = member.getUser()
+        else:
+            # Fallback in case we cannot find a user
+            # with the given userid
+            user = getSecurityManager().getUser()
+
         login_time = user.getProperty('login_time', None)
         if login_time is None:
             notify(UserInitialLoginInEvent(user))

{"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@@ -10,6 +10,7 @@\n from Products.CMFPlone.interfaces.controlpanel import IMailSchema\n from Products.CMFPlone.PasswordResetTool import ExpiredRequestError\n from Products.CMFPlone.PasswordResetTool import InvalidRequestError\n+from Products.CMFPlone.RegistrationTool import get_member_by_login_name\n from Products.CMFPlone.utils import safe_unicode\n from Products.CMFPlone.utils import safeToInt\n from Products.Five import BrowserView\n@@ -89,7 +90,8 @@\n     subpath = None\n \n     def _auto_login(self, userid, password):\n-        aclu = getToolByName(self.context, 'acl_users')\n+        context = self.context\n+        aclu = getToolByName(context, 'acl_users')\n         for name, plugin in aclu.plugins.listPlugins(ICredentialsUpdatePlugin):\n             plugin.updateCredentials(\n                 self.request,\n@@ -97,7 +99,16 @@\n                 userid,\n                 password\n             )\n-        user = getSecurityManager().getUser()\n+\n+        member = get_member_by_login_name(context, userid, False)\n+\n+        if member:\n+            user = member.getUser()\n+        else:\n+            # Fallback in case we cannot find a user\n+            # with the given userid\n+            user = getSecurityManager().getUser()\n+\n         login_time = user.getProperty('login_time', None)\n         if login_time is None:\n             notify(UserInitialLoginInEvent(user))\n", "issue": "Login user after password reset notify events with Anonymous User\n## BUG/PROBLEM REPORT\r\n\r\nThe option **Login user after password reset** allows a user that just performed a password reset to automatically log in after the .process is complete.\r\n\r\nOne of the two events (**UserLoggedInEvent**, **UserInitialLoginInEvent**) is triggered by this process, but with the Anonymous User instead of the user that just performed the password request.\r\n\r\n### What I did:\r\n\r\n- Newly created Plone site (no addons)\r\n- **Login user after password reset** selected on */@@security-controlpanel*\r\n- Create a new user\r\n- Request a reset user password\r\n- Follow the generated link\r\n\r\n### What I expect to happen:\r\n\r\n**UserLoggedInEvent** or **UserInitialLoginInEvent** should be triggered with the newly logged in user.\r\n\r\n### What actually happened:\r\n\r\n**UserLoggedInEvent** and **UserInitialLoginInEvent** are triggrered with **<SpecialUser 'Anonymous User'>**.\r\n\r\n### What version of Plone/ Addons I am using:\r\n\r\n* Plone 5.2\r\n* No addons\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        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"}], "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.RegistrationTool import get_member_by_login_name\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        context = self.context\n        aclu = getToolByName(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\n        member = get_member_by_login_name(context, userid, False)\n\n        if member:\n            user = member.getUser()\n        else:\n            # Fallback in case we cannot find a user\n            # with the given userid\n            user = getSecurityManager().getUser()\n\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"}]}