Methods are added to the AccountChangeListener interface for password
reset and user email verification to decouple trac/notification.py and
accountmanagerplugin.  This change will enable a full-featured
announcerplugin module to replacate the accountmanagerplugin
notification behavior.
---
 acct_mgr/api.py          |   15 ++++++
 acct_mgr/notification.py |   79 +++++++++++++++++++++++++++++++++
 acct_mgr/web_ui.py       |  110 ++++++++++------------------------------------
 3 files changed, 117 insertions(+), 87 deletions(-)

diff --git a/acct_mgr/api.py b/acct_mgr/api.py
index d7963b3..caf2140 100644
--- a/acct_mgr/api.py
+++ b/acct_mgr/api.py
@@ -77,6 +77,14 @@ class IAccountChangeListener(Interface):
         """User deleted
         """
 
+    def user_password_reset(self, user, email, password):
+        """User password reset
+        """
+
+    def user_email_verification_requested(self, user, token):
+        """User verification requested
+        """
+
 class AccountManager(Component):
     """The AccountManager component handles all user account management methods
     provided by the IPasswordStore interface.
@@ -248,3 +256,10 @@ class AccountManager(Component):
     def user_deleted(self, user):
         self.log.info('Deleted user: %s' % user)
 
+    def user_password_reset(self, user, email, password):
+        self.log.info('Password reset user: %s, %s'%(user, email))
+        
+    def user_email_verification_requested(self, user, token):
+        self.log.info('Email verification requested user: %s' % user)
+
+
diff --git a/acct_mgr/notification.py b/acct_mgr/notification.py
index e966855..e840c5b 100644
--- a/acct_mgr/notification.py
+++ b/acct_mgr/notification.py
@@ -50,6 +50,17 @@ class AccountChangeListener(Component):
             notifier = AccountChangeNotification(self.env)
             notifier.notify(username, 'Deleted User')
 
+    def user_password_reset(self, username, email, password):
+        notifier = PasswordResetNotification(self.env)
+        if email != notifier.email_map.get(username):
+            raise Exception('The email and username do not '
+                            'match a known account.')
+        notifier.notify(username, password)
+
+    def user_email_verification_requested(self, username, token):
+        notifier = EmailVerificationNotification(self.env)
+        notifier.notify(username, token)
+
 class AccountChangeNotification(NotifyEmail):
     template_name = 'user_changes_email.txt'
 
@@ -154,6 +165,74 @@ class AccountChangeNotification(NotifyEmail):
         self.server.sendmail(msg['From'], recipients, msgtext)
 
 
+class SingleUserNotification(NotifyEmail):
+    """Helper class used for account email notifications which should only be
+    sent to one persion, not including the rest of the normally CCed users
+    """
+    _username = None
+
+    def get_recipients(self, resid):
+        return ([resid],[])
+
+    def get_smtp_address(self, addr):
+        """Overrides `get_smtp_address` in order to prevent CCing users
+        other than the user whose password is being reset.
+        """
+        if addr == self._username:
+            return NotifyEmail.get_smtp_address(self, addr)
+        else:
+            return None
+
+    def notify(self, username, subject):
+        # save the username for use in `get_smtp_address`
+        self._username = username
+        old_public_cc = self.config.getbool('notification', 'use_public_cc')
+        # override public cc option so that the user's email is included in 
the To: field
+        self.config.set('notification', 'use_public_cc', 'true')
+        try:
+            NotifyEmail.notify(self, username, subject)
+        finally:
+            self.config.set('notification', 'use_public_cc', old_public_cc)
+
+
+class PasswordResetNotification(SingleUserNotification):
+    template_name = 'reset_password_email.txt'
+
+    def notify(self, username, password):
+        self.data.update({
+            'account': {
+                'username': username,
+                'password': password,
+            },
+            'login': {
+                'link': self.env.abs_href.login(),
+            }
+        })
+
+        projname = self.config.get('project', 'name')
+        subject = '[%s] Trac password reset for user: %s' % (projname, 
username)
+
+        SingleUserNotification.notify(self, username, subject)
+
+
+class EmailVerificationNotification(SingleUserNotification):
+    template_name = 'verify_email.txt'
+
+    def notify(self, username, token):
+        self.data.update({
+            'account': {
+                'username': username,
+                'token': token,
+            },
+            'verify': {
+                'link': self.env.abs_href.verify_email(token=token),
+            }
+        })
+
+        projname = self.config.get('project', 'name')
+        subject = '[%s] Trac email verification for user: %s' % (projname, 
username)
+
+        SingleUserNotification.notify(self, username, subject)
 
 
 class AccountChangeNotificationAdminPanel(Component):
diff --git a/acct_mgr/web_ui.py b/acct_mgr/web_ui.py
index 4bd3303..7ebceff 100644
--- a/acct_mgr/web_ui.py
+++ b/acct_mgr/web_ui.py
@@ -16,8 +16,7 @@ import string
 
 from trac import perm, util
 from trac.core import *
-from trac.config import IntOption
-from trac.notification import NotificationSystem, NotifyEmail
+from trac.config import IntOption, BoolOption
 from trac.prefs import IPreferencePanelProvider
 from trac.web import auth
 from trac.web.api import IAuthenticator
@@ -96,56 +95,6 @@ def _create_user(req, env, check_permissions=True):
     db.commit()
 
 
-class SingleUserNotification(NotifyEmail):
-    """Helper class used for account email notifications which should only be
-    sent to one persion, not including the rest of the normally CCed users
-    """
-    _username = None
-
-    def get_recipients(self, resid):
-        return ([resid],[])
-
-    def get_smtp_address(self, addr):
-        """Overrides `get_smtp_address` in order to prevent CCing users
-        other than the user whose password is being reset.
-        """
-        if addr == self._username:
-            return NotifyEmail.get_smtp_address(self, addr)
-        else:
-            return None
-
-    def notify(self, username, subject):
-        # save the username for use in `get_smtp_address`
-        self._username = username
-        old_public_cc = self.config.getbool('notification', 'use_public_cc')
-        # override public cc option so that the user's email is included in 
the To: field
-        self.config.set('notification', 'use_public_cc', 'true')
-        try:
-            NotifyEmail.notify(self, username, subject)
-        finally:
-            self.config.set('notification', 'use_public_cc', old_public_cc)
-
-
-class PasswordResetNotification(SingleUserNotification):
-    template_name = 'reset_password_email.txt'
-
-    def notify(self, username, password):
-        self.data.update({
-            'account': {
-                'username': username,
-                'password': password,
-            },
-            'login': {
-                'link': self.env.abs_href.login(),
-            }
-        })
-
-        projname = self.config.get('project', 'name')
-        subject = '[%s] Trac password reset for user: %s' % (projname, 
username)
-
-        SingleUserNotification.notify(self, username, subject)
-
-
 class AccountModule(Component):
     """Allows users to change their password, reset their password if they've
     forgotten it, or delete their account.  The settings for the AccountManager
@@ -161,6 +110,10 @@ class AccountModule(Component):
                                 'created when resetting the password for an '
                                 'account.')
 
+    reset_password = BoolOption('account-manager', 'reset_password',
+                                True, 'Set to false if there is no email '
+                                'system setup.')
+
     def __init__(self):
         self._write_check(log=True)
 
@@ -219,7 +172,7 @@ class AccountModule(Component):
 
     def reset_password_enabled(self):
         return (self.env.is_component_enabled(AccountModule)
-                and NotificationSystem(self.env).smtp_enabled
+                and self.reset_password
                 and self._write_check())
     reset_password_enabled = property(reset_password_enabled)
 
@@ -263,15 +216,12 @@ class AccountModule(Component):
         if not email:
             return {'error': 'Email is required'}
 
-        notifier = PasswordResetNotification(self.env)
-
-        if email != notifier.email_map.get(username):
-            return {'error': 'The email and username do not '
-                             'match a known account.'}
-
         new_password = self._random_password()
-        notifier.notify(username, new_password)
         mgr = AccountManager(self.env)
+        try:
+            mgr._notify('password_reset', username, email, new_password)
+        except Exception, e:
+            return {'error': ','.join(e.args)}
         mgr.set_password(username, new_password)
         if mgr.force_passwd_change:
             db = self.env.get_db_cnx()
@@ -402,7 +352,7 @@ class RegistrationModule(Component):
                 req.redirect(req.href.login())
         data['reset_password_enabled'] = \
             (self.env.is_component_enabled(AccountModule)
-             and NotificationSystem(self.env).smtp_enabled)
+             and AccountModule(self.env).reset_password)
 
         return 'register.html', data, None
 
@@ -500,26 +450,6 @@ class LoginModule(auth.LoginModule):
         return [resource_filename(__name__, 'templates')]
 
 
-class EmailVerificationNotification(SingleUserNotification):
-    template_name = 'verify_email.txt'
-
-    def notify(self, username, token):
-        self.data.update({
-            'account': {
-                'username': username,
-                'token': token,
-            },
-            'verify': {
-                'link': self.env.abs_href.verify_email(token=token),
-            }
-        })
-
-        projname = self.config.get('project', 'name')
-        subject = '[%s] Trac email verification for user: %s' % (projname, 
username)
-
-        SingleUserNotification.notify(self, username, subject)
-
-
 class EmailVerificationModule(Component):
     implements(IRequestFilter, IRequestHandler)
 
@@ -551,7 +481,12 @@ class EmailVerificationModule(Component):
         if email and email != req.session.get('email_verification_sent_to'):
             req.session['email_verification_token'] = self._gen_token()
             req.session['email_verification_sent_to'] = email
-            self._send_email(req)
+            mgr = AccountManager(self.env)
+            mgr._notify(
+                'email_verification_requested', 
+                req.authname, 
+                req.session['email_verification_token']
+            )
             chrome.add_notice(req, Markup(tag.span(
                     'An email has been sent to ', email,
                     ' with a token to ',
@@ -570,7 +505,12 @@ class EmailVerificationModule(Component):
         elif req.method != 'POST':
             pass
         elif 'resend' in req.args:
-            self._send_email(req)
+            mgr = AccountManager(self.env)
+            mgr._notify(
+                'email_verification_requested', 
+                req.authname, 
+                req.session['email_verification_token']
+            )
             chrome.add_notice(req,
                     'A notification email has been resent to %s.',
                     req.session.get('email'))
@@ -587,7 +527,3 @@ class EmailVerificationModule(Component):
 
     def _gen_token(self):
         return base64.urlsafe_b64encode(urandom(6))
-
-    def _send_email(self, req):
-        notifier = EmailVerificationNotification(self.env)
-        notifier.notify(req.authname, req.session['email_verification_token'])
-- 
1.6.4.4

_______________________________________________
th-users mailing list
[email protected]
https://lists.trac-hacks.org/mailman/listinfo/th-users

Reply via email to