X-Git-Url: https://scm.cri.minesparis.psl.eu/git/Plinn.git/blobdiff_plain/3c4367d8e03450e9a73e61f4247145d2b6c86a33..959d888c17d1403d2eeecc19bc4b5e2c8d1debf6:/RegistrationTool.py diff --git a/RegistrationTool.py b/RegistrationTool.py deleted file mode 100644 index 8c2911d..0000000 --- a/RegistrationTool.py +++ /dev/null @@ -1,304 +0,0 @@ -# -*- coding: utf-8 -*- -####################################################################################### -# Plinn - http://plinn.org # -# © 2005-2013 Benoît PIN # -# # -# This program is free software; you can redistribute it and/or # -# modify it under the terms of the GNU General Public License # -# as published by the Free Software Foundation; either version 2 # -# of the License, or (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program; if not, write to the Free Software # -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -####################################################################################### -""" Plinn registration tool: implements 3 modes to register members: - anonymous, manager, reviewed. - - - -""" - -from Globals import InitializeClass, PersistentMapping -from Products.PageTemplates.PageTemplateFile import PageTemplateFile -from Products.CMFDefault.RegistrationTool import RegistrationTool as BaseRegistrationTool -from AccessControl import ClassSecurityInfo, ModuleSecurityInfo -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 - -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_PASS_ANONYMOUS, MODE_MANAGER, MODE_REVIEWED] -security.declarePublic('MODES') - -DEFAULT_MEMBER_GROUP = 'members' -security.declarePublic('DEFAULT_MEMBER_GROUP') - - - -class RegistrationTool(BaseRegistrationTool) : - - """ Create and modify users by making calls to portal_membership. - """ - - meta_type = "Plinn Registration Tool" - - manage_options = ({'label' : 'Registration mode', 'action' : 'manage_regmode'}, ) + \ - BaseRegistrationTool.manage_options - - security = ClassSecurityInfo() - - security.declareProtected( ManagePortal, 'manage_regmode' ) - manage_regmode = PageTemplateFile('www/configureRegistrationTool', globals(), - __name__='manage_regmode') - - def __init__(self) : - self._mode = MODE_ANONYMOUS - self._chain = '' - self._passwordResetRequests = OOBTree() - - security.declareProtected(ManagePortal, 'configureTool') - def configureTool(self, registration_mode, chain, REQUEST=None) : - """ """ - - if registration_mode not in MODES : - raise ValueError, "Unknown mode: " + registration_mode - else : - self._mode = registration_mode - self._updatePortalRoleMappingForMode(registration_mode) - - wtool = getToolByName(self, 'portal_workflow') - - if registration_mode == MODE_REVIEWED : - if not hasattr(wtool, '_chains_by_type') : - wtool._chains_by_type = PersistentMapping() - wfids = [] - chain = chain.strip() - - if chain == '(Default)' : - try : del wtool._chains_by_type['Member Data'] - except KeyError : pass - self._chain = chain - else : - for wfid in chain.replace(',', ' ').split(' ') : - if wfid : - if not wtool.getWorkflowById(wfid) : - raise ValueError, '"%s" is not a workflow ID.' % wfid - wfids.append(wfid) - - wtool._chains_by_type['Member Data'] = tuple(wfids) - self._chain = ', '.join(wfids) - else : - wtool._chains_by_type['Member Data'] = tuple() - - if REQUEST : - REQUEST.RESPONSE.redirect(self.absolute_url() + '/manage_regmode?manage_tabs_message=Saved changes.') - - def _updatePortalRoleMappingForMode(self, mode) : - - urlTool = getToolByName(self, 'portal_url') - portal = urlTool.getPortalObject() - - 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) - - security.declarePublic('getMode') - def getMode(self) : - # """ return current mode """ - return self._mode[:] - - security.declarePublic('getWfId') - def getWfChain(self) : - # """ return current workflow id """ - return self._chain - - security.declarePublic('roleMappingMismatch') - def roleMappingMismatch(self) : - # """ test if the role mapping is correct for the currrent mode """ - - mode = self._mode - urlTool = getToolByName(self, 'portal_url') - portal = urlTool.getPortalObject() - - def rolesOfAddPortalMemberPerm() : - p=Permission(AddPortalMember, [], portal) - return p.getRoles() - - if mode in [MODE_ANONYMOUS, MODE_PASS_ANONYMOUS, MODE_REVIEWED] : - if 'Anonymous' in rolesOfAddPortalMemberPerm() : return False - - elif mode == MODE_MANAGER : - roles = rolesOfAddPortalMemberPerm() - if 'Manager' in roles or 'UserManager' in roles and len(roles) == 1 and type(roles) == TupleType : - return False - - return True - - security.declareProtected(AddPortalMember, 'addMember') - def addMember(self, id, password, roles=(), groups=(DEFAULT_MEMBER_GROUP,), domains='', properties=None) : - """ Idem CMFCore but without default role """ - - 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 - - for gid in groups: - g = gtool.getGroupById(gid) - if not isGrpManager : - if gid != DEFAULT_MEMBER_GROUP: - raise AccessControl_Unauthorized, 'You are not allowed to join arbitrary group.' - - if g is None : - gtool.addGroup(gid) - 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): - """ notify member creation """ - member.notifyWorkflowCreated() - member.indexObject() - - - security.declarePublic('requestPasswordReset') - def requestPasswordReset(self, userid): - """ add uuid / (userid, expiration) pair and return uuid """ - 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) - utool = getUtilityByInterfaceName('Products.CMFCore.interfaces.IURLTool') - 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, - 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): - now = DateTime() - for uuid, record in self._passwordResetRequests.items() : - userid, date = record - if date < now : - del self._passwordResetRequests[uuid] - - - security.declarePublic('resetPassword') - def resetPassword(self, uuid, password, confirm) : - record = self._passwordResetRequests.get(uuid) - if not record : - return None, _('Invalid reset password request.') - - userid, expiration = record - now = DateTime() - if expiration < now : - self.clearExpiredPasswordResetRequests() - 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. - mtool = getUtilityByInterfaceName('Products.CMFCore.interfaces.IMembershipTool') - member = mtool.getMemberById(userid) - if member : - member.setSecurityProfile(password=password) - del self._passwordResetRequests[uuid] - return userid, _('Password successfully updated.') - else : - return None, _('"%s" username not found.') % userid - - -InitializeClass(RegistrationTool) \ No newline at end of file