more on registration; extend concept view to show the attributes of the typeInterface

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1222 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-05-23 17:32:17 +00:00
parent 00e27595ca
commit 6ab11a50e9
8 changed files with 110 additions and 52 deletions

View file

@ -68,7 +68,18 @@ class ConceptView(BaseView):
@Lazy
def macro(self):
return self.template.macros['conceptlisting']
return self.template.macros['conceptdata']
def fieldData(self):
ti = IType(self.context).typeInterface
if not ti: return
adapter = ti(self.context)
for f in ti:
title = getattr(ti[f], 'title', '')
value = getattr(adapter, f, '')
if not (value and title):
continue
yield {'title': title, 'value': value, 'id': f}
def children(self):
for r in self.context.getChildRelations():

View file

@ -1,4 +1,23 @@
<metal:body define-macro="conceptlisting">
<metal:data define-macro="conceptdata">
<div tal:attributes="class string:content-$level;
ondblclick item/openEditWindow">
<h3>
<span i18n:translate="">Concept</span>:
<span tal:content="item/title">Title</span>
</h3>
<table>
<tr tal:repeat="field item/fieldData">
<td><span tal:content="field/title"
i18n:translate="" />:</td>
<td tal:content="nocall:field/value"></td>
</tr>
</table>
<metal:listing use-macro="item/template/macros/conceptlisting2" />
</div>
</metal:data>
<metal:listing define-macro="conceptlisting">
<div>
<h3 tal:attributes="class string:content-$level;
ondblclick item/openEditWindow">
@ -12,7 +31,7 @@
<div tal:repeat="related item/parents">
<a href="#"
tal:attributes="href string:${view/url}/.target${related/uniqueId}"
tal:content="related/title">Resource Title</a>
tal:content="related/title">Concept Title</a>
</div>
</div>
<div tal:attributes="class string:content-$level;
@ -21,7 +40,7 @@
<div tal:repeat="related item/children">
<a href="#"
tal:attributes="href string:${view/url}/.target${related/uniqueId}"
tal:content="related/title">Resource Title</a>
tal:content="related/title">Concept Title</a>
</div>
</div>
<div tal:attributes="class string:content-$level;
@ -35,4 +54,4 @@
</div>
</metal:listing>
</div>
</metal:body>
</metal:listing>

View file

@ -223,7 +223,7 @@ and register it
>>> personAdapter = regView.register(data)
>>> personAdapter.context.__name__, personAdapter.lastName, personAdapter.userId
(u'newuser', u'Sawyer', u'loops.newuser')
(u'person.newuser', u'Sawyer', u'loops.newuser')
Now we can also retrieve it from the authentication utility:

View file

@ -34,22 +34,17 @@ from zope.formlib.form import Form, FormFields, action
from zope.formlib.namedtemplate import NamedTemplate
from zope.i18nmessageid import MessageFactory
from loops.browser.common import BaseView
from cybertools.typology.interfaces import IType
from loops.browser.concept import ConceptView
from loops.browser.node import NodeView
from loops.browser.concept import ConceptRelationView
from loops.organize.interfaces import ANNOTATION_KEY, IMemberRegistrationManager
from loops.organize.interfaces import IMemberRegistration, raiseValidationError
from loops.organize.interfaces import IMemberRegistration
_ = MessageFactory('zope')
class MyConcepts(BaseView):
template = NamedTemplate('loops.concept_macros')
@Lazy
def macro(self):
return self.template.macros['conceptlisting']
class MyStuff(ConceptView):
def __init__(self, context, request):
self.context = context
@ -59,23 +54,9 @@ class MyConcepts(BaseView):
if self.person is not None:
self.context = self.person
def children(self):
if self.person is None:
return
for r in self.person.getChildRelations():
yield ConceptRelationView(r, self.request, contextIsSecond=True)
def parents(self):
if self.person is None:
return
for r in self.person.getParentRelations():
yield ConceptRelationView(r, self.request)
def resources(self):
if self.person is None:
return
for r in self.person.getResourceRelations():
yield ConceptRelationView(r, self.request, contextIsSecond=True)
@Lazy
def view(self):
return self
class PasswordWidget(BasePasswordWidget):
@ -109,11 +90,13 @@ class MemberRegistration(Form, NodeView):
pw = form.get('password')
if form.get('passwordConfirm') != pw:
raise ValueError(u'Password and password confirmation do not match.')
login = form.get('loginName')
regMan = IMemberRegistrationManager(self.context.getLoopsRoot())
person = regMan.register(form.get('loginName'), pw,
person = regMan.register(login, pw,
form.get('lastName'),
form.get('firstName'))
message = _(u'You have been registered and can now login.')
self.request.response.redirect('%s?message=%s' % (self.url, message))
self.request.response.redirect('%s/login.html?login=%s&message=%s'
% (self.url, login, message))
return person

View file

@ -28,11 +28,11 @@
<!-- my stuff and other views -->
<zope:adapter
name="myconcepts"
name="mystuff"
for="loops.interfaces.IConcept
zope.publisher.interfaces.browser.IBrowserRequest"
provides="zope.interface.Interface"
factory="loops.organize.browser.MyConcepts"
factory="loops.organize.browser.MyStuff"
permission="zope.View"
/>

View file

@ -28,7 +28,10 @@ from zope.app import zapi
from zope.app.principalannotation import annotations
from zope.app.security.interfaces import IAuthentication, PrincipalLookupError
from zope.i18nmessageid import MessageFactory
from zope.security.proxy import removeSecurityProxy
from cybertools.organize.interfaces import IPerson as IBasePerson
from loops.organize.util import getPrincipalFolder, authPluginId
_ = MessageFactory('zope')
@ -50,7 +53,8 @@ class UserId(schema.TextLine):
def _validate(self, userId):
if not userId:
return
auth = component.getUtility(IAuthentication, context=self.context)
context = removeSecurityProxy(self.context).context
auth = component.getUtility(IAuthentication, context=context)
try:
principal = auth.getPrincipal(userId)
except PrincipalLookupError:
@ -58,7 +62,7 @@ class UserId(schema.TextLine):
mapping={'userId': userId}))
pa = annotations(principal)
person = pa.get(ANNOTATION_KEY, None)
if person is not None and person != self.context:
if person is not None and person != context:
raiseValidationError(
_(u'There is alread a person ($person) assigned to user $userId.',
mapping=dict(person=zapi.getName(person),
@ -69,6 +73,10 @@ class LoginName(schema.TextLine):
def _validate(self, userId):
super(LoginName, self)._validate(userId)
if userId in getPrincipalFolder(self.context):
raiseValidationError(
_(u'There is alread a user with ID $userId.',
mapping=dict(userId=userId)))
class Password(schema.Password):

View file

@ -39,6 +39,7 @@ 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.util import getPrincipalFolder, authPluginId
_ = MessageFactory('zope')
@ -48,40 +49,32 @@ 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):
raise ValueError(u'There is no pluggable authentication '
'utility available.')
if not self.authPluginId in pau.authenticatorPlugins:
raise ValueError(u'There is no loops authenticator '
'plugin available.')
pFolder = component.queryUtility(IAuthenticatorPlugin, self.authPluginId,
context=pau)
pFolder = getPrincipalFolder(self.context)
title = firstName and ' '.join((firstName, lastName)) or lastName
# TODO: care for password encryption:
principal = InternalPrincipal(userId, password, title)
pFolder[userId] = principal
# step 2: create a corresponding person concept:
cm = self.context.getConceptManager()
id = userId
id = baseId = 'person.' + userId
num = 0
while id in cm:
num +=1
id = userId + str(num)
id = baseId + str(num)
person = cm[id] = Concept(title)
# TODO: the name of the person type object must be kept flexible!
# So we have to search for a type concept that has IPerson as
# its typeInterface...
person.conceptType = cm['person']
personAdapter = IType(person).typeInterface(person)
personAdapter.firstName = firstName
personAdapter.lastName = lastName
personAdapter.userId = '.'.join((self.authPluginId, userId))
personAdapter.userId = '.'.join((authPluginId, userId))
notify(ObjectCreatedEvent(person))
notify(ObjectModifiedEvent(person))
return personAdapter

44
organize/util.py Normal file
View file

@ -0,0 +1,44 @@
#
# 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
#
"""
Utilities for the loops.organize package.
$Id$
"""
from zope.app import zapi
from zope import interface, component, schema
from zope.app.authentication.interfaces import IPluggableAuthentication
from zope.app.authentication.interfaces import IAuthenticatorPlugin
from zope.app.security.interfaces import IAuthentication
authPluginId = 'loops'
def getPrincipalFolder(context=None):
pau = zapi.getUtility(IAuthentication, context=context)
if not IPluggableAuthentication.providedBy(pau):
raise ValueError(u'There is no pluggable authentication '
'utility available.')
if not authPluginId in pau.authenticatorPlugins:
raise ValueError(u'There is no loops authenticator '
'plugin available.')
return component.queryUtility(IAuthenticatorPlugin, authPluginId,
context=pau)