Work in progress: self-service registration (member registration)
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1220 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
c55d35f902
commit
a70fe7d830
5 changed files with 205 additions and 10 deletions
|
@ -1,5 +1,5 @@
|
|||
<metal:block define-macro="render">
|
||||
<div>
|
||||
<div tal:attributes="ondblclick python: item.openEditWindow('configure.html')">
|
||||
<h3 tal:content="item/title">Title</h3>
|
||||
<span tal:replace="structure item/render" />
|
||||
</div>
|
||||
|
@ -7,7 +7,7 @@
|
|||
|
||||
|
||||
<metal:block define-macro="image">
|
||||
<div>
|
||||
<div tal:attributes="ondblclick python: item.openEditWindow('edit.html')">
|
||||
<h3 tal:content="item/title">Title</h3>
|
||||
<img src="#"
|
||||
tal:attributes="src string:${view/url}/.target${view/targetId}/view" />
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
|
||||
<metal:block define-macro="download">
|
||||
<div>
|
||||
<div tal:attributes="ondblclick python: item.openEditWindow('edit.html')">
|
||||
<h3 tal:content="item/title">Title</h3>
|
||||
<a href="#"
|
||||
tal:attributes="href string:${view/url}/.target${view/targetId}/view">
|
||||
|
|
|
@ -6,7 +6,7 @@ loops - Linked Objects for Organization and Processing Services
|
|||
|
||||
Note: This packages depends on cybertools.organize.
|
||||
|
||||
Letz's do some basic set up
|
||||
Let's do some basic set up
|
||||
|
||||
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
||||
>>> site = placefulSetUp(True)
|
||||
|
@ -161,9 +161,75 @@ concept assigned we should get an error:
|
|||
|
||||
>>> martha.userId = 'users.john'
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
...
|
||||
ValueError: ...
|
||||
|
||||
|
||||
Member Registrations
|
||||
====================
|
||||
|
||||
The member registration needs the whole pluggable authentication stuff
|
||||
with a principal folder:
|
||||
|
||||
>>> from zope.app.appsetup.bootstrap import ensureUtility
|
||||
>>> from zope.app.authentication.authentication import PluggableAuthentication
|
||||
>>> ensureUtility(site, IAuthentication, '', PluggableAuthentication,
|
||||
... copy_to_zlog=False)
|
||||
''
|
||||
>>> pau = component.getUtility(IAuthentication, context=site)
|
||||
|
||||
>>> from zope.app.component.site import UtilityRegistration
|
||||
>>> from zope.app.authentication.principalfolder import PrincipalFolder
|
||||
>>> from zope.app.authentication.interfaces import IAuthenticatorPlugin
|
||||
>>> pFolder = PrincipalFolder('loops.')
|
||||
>>> pau['loops'] = pFolder
|
||||
>>> reg = UtilityRegistration('loops', IAuthenticatorPlugin, pFolder)
|
||||
>>> pau.registrationManager.addRegistration(reg)
|
||||
'UtilityRegistration'
|
||||
>>> reg.status = u'Active'
|
||||
>>> pau.authenticatorPlugins = ('loops',)
|
||||
|
||||
In addition, we have to create at least one node in the view space
|
||||
and register an IMemberRegistrationManager adapter for the loops root object:
|
||||
|
||||
>>> from loops.view import ViewManager, Node
|
||||
>>> views = loopsRoot['views'] = ViewManager()
|
||||
>>> menu = views['menu'] = Node('Home')
|
||||
>>> menu.nodeType = 'menu'
|
||||
|
||||
>>> from loops.organize.member import MemberRegistrationManager
|
||||
>>> from loops.organize.interfaces import IMemberRegistrationManager
|
||||
>>> from loops.interfaces import ILoops
|
||||
>>> component.provideAdapter(MemberRegistrationManager)
|
||||
|
||||
Now we can enter the registration info for a new member (after having made
|
||||
sure that a principal object can be served by a corresponding factory):
|
||||
|
||||
>>> from zope.app.authentication.principalfolder import FoundPrincipalFactory
|
||||
>>> component.provideAdapter(FoundPrincipalFactory)
|
||||
|
||||
>>> form = {'field.userId': u'newuser',
|
||||
... 'field.passwd': u'quack',
|
||||
... 'field.passwdConfirm': u'quack',
|
||||
... 'field.lastName': u'Sawyer',
|
||||
... 'field.firstName': u'Tom'}
|
||||
>>> from zope.publisher.browser import TestRequest
|
||||
>>> request = TestRequest(form=form)
|
||||
|
||||
and register it
|
||||
|
||||
>>> from loops.organize.browser import MemberRegistration
|
||||
>>> regView = MemberRegistration(menu, request)
|
||||
>>> personAdapter = regView.register()
|
||||
|
||||
>>> personAdapter.context.__name__, personAdapter.lastName, personAdapter.userId
|
||||
(u'newuser', u'Sawyer', u'loops.newuser')
|
||||
|
||||
Now we can also retrieve it from the authentication utility:
|
||||
|
||||
>>> pau.getPrincipal('loops.newuser').title
|
||||
u'Tom Sawyer'
|
||||
|
||||
|
||||
Fin de partie
|
||||
=============
|
||||
|
|
|
@ -28,10 +28,14 @@ from zope.app import zapi
|
|||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.app.principalannotation import annotations
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.i18nmessageid import MessageFactory
|
||||
|
||||
from loops.browser.common import BaseView
|
||||
from loops.browser.concept import ConceptRelationView
|
||||
from loops.organize.interfaces import ANNOTATION_KEY
|
||||
from loops.organize.interfaces import ANNOTATION_KEY, IMemberRegistrationManager
|
||||
from loops.organize.interfaces import raiseValidationError
|
||||
|
||||
_ = MessageFactory('zope')
|
||||
|
||||
|
||||
class MyConcepts(BaseView):
|
||||
|
@ -65,6 +69,22 @@ class MyConcepts(BaseView):
|
|||
for r in self.person.getResourceRelations():
|
||||
yield ConceptRelationView(r, self.request, contextIsSecond=True)
|
||||
|
||||
@Lazy
|
||||
def view(self):
|
||||
return self
|
||||
|
||||
class MemberRegistration(object):
|
||||
|
||||
def __init__(self, context, request):
|
||||
self.context = context
|
||||
self.request = request
|
||||
|
||||
def register(self):
|
||||
form = self.request.form
|
||||
pw = form.get('field.passwd')
|
||||
if form.get('field.passwdConfirm') != pw:
|
||||
raiseValidationError(_(u'Password and password confirmation '
|
||||
'do not match.'))
|
||||
regMan = IMemberRegistrationManager(self.context.getLoopsRoot())
|
||||
person = regMan.register(form.get('field.userId'), pw,
|
||||
form.get('field.lastName'),
|
||||
form.get('field.firstName'))
|
||||
return person
|
||||
|
||||
|
|
|
@ -61,7 +61,8 @@ class UserId(schema.TextLine):
|
|||
if person is not None and person != self.context:
|
||||
raiseValidationError(
|
||||
_(u'There is alread a person ($person) assigned to user $userId.',
|
||||
mapping={'person': zapi.getName(person), 'userId': userId}))
|
||||
mapping=dict(person=zapi.getName(person),
|
||||
userId=userId)))
|
||||
|
||||
|
||||
class IPerson(IBasePerson):
|
||||
|
@ -76,3 +77,23 @@ class IPerson(IBasePerson):
|
|||
description=_(u'The principal id of a user that should '
|
||||
'be associated with this person.'),
|
||||
required=False,)
|
||||
|
||||
|
||||
class IMemberRegistrationManager(Interface):
|
||||
""" Knows what to do for registrating a new member (portal user).
|
||||
"""
|
||||
|
||||
authPluginId = Attribute(u'The id of an authentication plugin to be '
|
||||
'used for managing members of this loops site')
|
||||
|
||||
def register(userId, password, lastName, firstName=u'', **kw):
|
||||
""" Register a new member for this loops site.
|
||||
Return the person adapter for the concept created.
|
||||
Raise ValidationError if the user could not be created.
|
||||
"""
|
||||
|
||||
def changePassword(oldPw, newPw):
|
||||
""" Change the password of the user currently logged-in.
|
||||
Raise a ValidationError if the oldPw does not match the
|
||||
current password.
|
||||
"""
|
||||
|
|
88
organize/member.py
Normal file
88
organize/member.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
#
|
||||
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Member registration adapter(s).
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.app import zapi
|
||||
from zope import interface, component
|
||||
from zope.component import adapts
|
||||
from zope.interface import implements
|
||||
from zope.app.authentication.interfaces import IPluggableAuthentication
|
||||
from zope.app.authentication.interfaces import IAuthenticatorPlugin
|
||||
from zope.app.authentication.principalfolder import InternalPrincipal
|
||||
from zope.app.security.interfaces import IAuthentication
|
||||
from zope.i18nmessageid import MessageFactory
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
|
||||
from cybertools.typology.interfaces import IType
|
||||
from loops.interfaces import ILoops
|
||||
from loops.concept import Concept
|
||||
from loops.organize.interfaces import IMemberRegistrationManager
|
||||
from loops.organize.interfaces import raiseValidationError
|
||||
|
||||
_ = MessageFactory('zope')
|
||||
|
||||
|
||||
class MemberRegistrationManager(object):
|
||||
|
||||
implements(IMemberRegistrationManager)
|
||||
adapts(ILoops)
|
||||
|
||||
authPluginId = 'loops'
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
def register(self, userId, password, lastName, firstName=u'', **kw):
|
||||
# step 1: create an internal principal in the loops principal folder:
|
||||
pau = zapi.getUtility(IAuthentication, context=self.context)
|
||||
if not IPluggableAuthentication.providedBy(pau):
|
||||
raiseValidationError(_(u'There is no pluggable authentication '
|
||||
'utility available.'))
|
||||
if not self.authPluginId in pau.authenticatorPlugins:
|
||||
raiseValidationError(_(u'There is no loops authenticator '
|
||||
'plugin available.'))
|
||||
pFolder = component.queryUtility(IAuthenticatorPlugin, self.authPluginId,
|
||||
context=pau)
|
||||
title = firstName and ' '.join((firstName, lastName)) or lastName
|
||||
# TODO: encrypt password:
|
||||
principal = InternalPrincipal(userId, password, title)
|
||||
pFolder[userId] = principal
|
||||
# step 1: create a corresponding person concept:
|
||||
cm = self.context.getConceptManager()
|
||||
id = userId
|
||||
num = 0
|
||||
while id in cm:
|
||||
num +=1
|
||||
id = userid + str(num)
|
||||
person = cm[id] = Concept(title)
|
||||
# TODO: the name of the person type object must be kept flexible!
|
||||
person.conceptType = cm['person']
|
||||
personAdapter = IType(person).typeInterface(person)
|
||||
personAdapter.firstName = firstName
|
||||
personAdapter.lastName = lastName
|
||||
personAdapter.userId = '.'.join((self.authPluginId, userId))
|
||||
return personAdapter
|
||||
|
||||
def changePassword(self, oldPw, newPw):
|
||||
pass
|
||||
|
Loading…
Add table
Reference in a new issue