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:
helmutm 2006-05-22 15:46:31 +00:00
parent c55d35f902
commit a70fe7d830
5 changed files with 205 additions and 10 deletions

View file

@ -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">

View file

@ -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
=============

View file

@ -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

View file

@ -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
View 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