style.
[Plinn.git] / RegistrationTool.py
index 953e008..8c2911d 100644 (file)
@@ -32,10 +32,15 @@ from AccessControl.Permission import Permission
 from BTrees.OOBTree import OOBTree
 from Products.CMFCore.permissions import ManagePortal, AddPortalMember
 from Products.CMFCore.exceptions import AccessControl_Unauthorized
+from Products.CMFDefault.exceptions import EmailAddressInvalid
 from Products.CMFCore.utils import getToolByName
 from Products.CMFCore.utils import getUtilityByInterfaceName
+from Products.CMFDefault.utils import checkEmailAddress
 from Products.GroupUserFolder.GroupsToolPermissions import ManageGroups
 from Products.Plinn.utils import Message as _
+from Products.Plinn.utils import translate
+from Products.Plinn.utils import encodeQuopriEmail
+from Products.Plinn.utils import encodeMailHeader
 from DateTime import DateTime
 from types import TupleType, ListType
 from uuid import uuid4
@@ -44,13 +49,16 @@ security = ModuleSecurityInfo('Products.Plinn.RegistrationTool')
 MODE_ANONYMOUS = 'anonymous'
 security.declarePublic('MODE_ANONYMOUS')
 
+MODE_PASS_ANONYMOUS = 'pass_anonymous'
+security.declarePublic('MODE_PASS_ANONYMOUS')
+
 MODE_MANAGER = 'manager'
 security.declarePublic('MODE_MANAGER')
 
 MODE_REVIEWED = 'reviewed'
 security.declarePublic('MODE_REVIEWED')
 
-MODES = [MODE_ANONYMOUS, MODE_MANAGER, MODE_REVIEWED]
+MODES = [MODE_ANONYMOUS, MODE_PASS_ANONYMOUS, MODE_MANAGER, MODE_REVIEWED]
 security.declarePublic('MODES')
 
 DEFAULT_MEMBER_GROUP = 'members'
@@ -121,7 +129,7 @@ class RegistrationTool(BaseRegistrationTool) :
         urlTool = getToolByName(self, 'portal_url')
         portal = urlTool.getPortalObject()
     
-        if mode in [MODE_ANONYMOUS, MODE_REVIEWED] :
+        if mode in [MODE_ANONYMOUS, MODE_PASS_ANONYMOUS, MODE_REVIEWED] :
             portal.manage_permission(AddPortalMember, roles = ['Anonymous', 'Manager'], acquire=1)
         elif mode == MODE_MANAGER :
             portal.manage_permission(AddPortalMember, roles = ['Manager', 'UserManager'], acquire=0)
@@ -148,7 +156,7 @@ class RegistrationTool(BaseRegistrationTool) :
             p=Permission(AddPortalMember, [], portal)
             return p.getRoles()
         
-        if mode in [MODE_ANONYMOUS, MODE_REVIEWED] :
+        if mode in [MODE_ANONYMOUS, MODE_PASS_ANONYMOUS, MODE_REVIEWED] :
             if 'Anonymous' in rolesOfAddPortalMemberPerm() : return False
             
         elif mode == MODE_MANAGER :
@@ -161,14 +169,34 @@ class RegistrationTool(BaseRegistrationTool) :
     security.declareProtected(AddPortalMember, 'addMember')
     def addMember(self, id, password, roles=(), groups=(DEFAULT_MEMBER_GROUP,), domains='', properties=None) :
         """ Idem CMFCore but without default role """
-        BaseRegistrationTool.addMember(self, id, password, roles=roles,
-                                       domains=domains, properties=properties)
 
-        if self.getMode() in [MODE_ANONYMOUS, MODE_MANAGER] :
+        if self.getMode() != MODE_REVIEWED :
             gtool = getToolByName(self, 'portal_groups')
             mtool = getToolByName(self, 'portal_membership')
             utool = getToolByName(self, 'portal_url')
             portal = utool.getPortalObject()
+            
+            if self.getMode() == MODE_PASS_ANONYMOUS :
+                private_collections = portal.get('private_collections')
+                if not private_collections :
+                    raise AccessControl_Unauthorized()
+                    return
+                data = private_collections.data
+                lines = filter(None, [l.strip() for l in data.split('\n')])
+                assert len(lines) % 3 == 0
+                collecInfos = {}
+                for i in xrange(0, len(lines), 3) :
+                    collecInfos[lines[i]] = {'pw' : lines[i+1],
+                                             'path' : lines[i+2]}
+                if not (collecInfos.has_key(properties.get('collection_id')) and \
+                    collecInfos[properties.get('collection_id')]['pw'] == properties.get('collection_password')) :
+                    raise AccessControl_Unauthorized('Wrong primary credentials')
+                    return
+            
+            
+            BaseRegistrationTool.addMember(self, id, password, roles=roles,
+                                           domains=domains, properties=properties)
+
             isGrpManager = mtool.checkPermission(ManageGroups, portal) ## TODO : CMF2.1 compat
             aclu = self.aq_inner.acl_users
 
@@ -183,6 +211,9 @@ class RegistrationTool(BaseRegistrationTool) :
                 aclu.changeUser(aclu.getGroupPrefix() +gid, roles=['Member', ])
                 g = gtool.getGroupById(gid)
                 g.addMember(id)
+        else :
+            BaseRegistrationTool.addMember(self, id, password, roles=roles,
+                                           domains=domains, properties=properties)
 
 
     def afterAdd(self, member, id, password, properties):
@@ -197,16 +228,45 @@ class RegistrationTool(BaseRegistrationTool) :
         self.clearExpiredPasswordResetRequests()
         mtool = getUtilityByInterfaceName('Products.CMFCore.interfaces.IMembershipTool')
         member = mtool.getMemberById(userid)
+        if not member :
+            try :
+                checkEmailAddress(userid)
+                member = mtool.searchMembers('email', userid)
+                if member :
+                    userid = member[0]['username']
+                    member = mtool.getMemberById(userid)
+            except EmailAddressInvalid :
+                pass
         if member :
             uuid = str(uuid4())
+            while self._passwordResetRequests.has_key(uuid) :
+                uuid = str(uuid4())
             self._passwordResetRequests[uuid] = (userid, DateTime() + 1)
-            mailhost = getUtilityByInterfaceName('Products.MailHost.interfaces.IMailHost')
-            ptool = getUtilityByInterfaceName('Products.CMFCore.interfaces.IPropertiesTool')
             utool = getUtilityByInterfaceName('Products.CMFCore.interfaces.IURLTool')
-            sender = ptool.getProperty('email_from_address')
-            to = member.getProperty('email')
+            ptool = getUtilityByInterfaceName('Products.CMFCore.interfaces.IPropertiesTool')
+            # fuck : mailhost récupéré avec getUtilityByInterfaceName n'est pas correctement
+            # wrappé. Un « unrestrictedTraverse » ne marche pas.
+            # mailhost = getUtilityByInterfaceName('Products.MailHost.interfaces.IMailHost')
+            portal = utool.getPortalObject()
+            mailhost = portal.MailHost
+            sender = encodeQuopriEmail(ptool.getProperty('email_from_name'), ptool.getProperty('email_from_address'))
+            to = encodeQuopriEmail(member.getMemberFullName(nameBefore=0), member.getProperty('email'))
+            subject = translate(_('How to reset your password on the %s website')) % ptool.getProperty('title')
+            subject = encodeMailHeader(subject)
+            options = {'fullName' : member.getMemberFullName(nameBefore=0),
+                       'siteName' : ptool.getProperty('title'),
+                       'resetPasswordUrl' : '%s/password_reset_form/%s' % (utool(), uuid)}
+            body = self.password_reset_mail(options)
             message = self.echange_mail_template(From=sender,
-                                                 To=to)
+                                                 To=to,
+                                                 Subject=subject,
+                                                 ContentType = 'text/plain',
+                                                 charset = 'UTF-8',
+                                                 body=body)
+            mailhost.send(message)
+            return
+        
+        return _('Unknown user name. Please retry.')
     
     security.declarePrivate('clearExpiredPasswordResetRequests')
     def clearExpiredPasswordResetRequests(self):
@@ -218,19 +278,16 @@ class RegistrationTool(BaseRegistrationTool) :
     
     
     security.declarePublic('resetPassword')
-    def resetPassword(self, userid, uuid, password, confirm) :
+    def resetPassword(self, uuid, password, confirm) :
         record = self._passwordResetRequests.get(uuid)
         if not record :
-            return _('Invalid reset password request.')
-        
-        recUserid, expiration = record
-        
-        if recUserid != userid :
-            return _('Invalid userid.')
+            return None, _('Invalid reset password request.')
         
+        userid, expiration = record
+        now = DateTime()
         if expiration < now :
             self.clearExpiredPasswordResetRequests()
-            return _('Your reset password request has expired. You can ask a new one.')
+            return None, _('Your reset password request has expired. You can ask a new one.')
         
         msg = self.testPasswordValidity(password, confirm=confirm)
         if not msg : # None if everything ok. Err message otherwise.
@@ -239,9 +296,9 @@ class RegistrationTool(BaseRegistrationTool) :
             if member :
                 member.setSecurityProfile(password=password)
                 del self._passwordResetRequests[uuid]
-                return _('Password successfully resetted.')
+                return  userid, _('Password successfully updated.')
             else :
-                return _('"%s" username not found.') % userid
+                return None, _('"%s" username not found.') % userid
             
         
 InitializeClass(RegistrationTool)
\ No newline at end of file