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 @Lazy
def macro(self): 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): def children(self):
for r in self.context.getChildRelations(): 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> <div>
<h3 tal:attributes="class string:content-$level; <h3 tal:attributes="class string:content-$level;
ondblclick item/openEditWindow"> ondblclick item/openEditWindow">
@ -12,7 +31,7 @@
<div tal:repeat="related item/parents"> <div tal:repeat="related item/parents">
<a href="#" <a href="#"
tal:attributes="href string:${view/url}/.target${related/uniqueId}" 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> </div>
<div tal:attributes="class string:content-$level; <div tal:attributes="class string:content-$level;
@ -21,7 +40,7 @@
<div tal:repeat="related item/children"> <div tal:repeat="related item/children">
<a href="#" <a href="#"
tal:attributes="href string:${view/url}/.target${related/uniqueId}" 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> </div>
<div tal:attributes="class string:content-$level; <div tal:attributes="class string:content-$level;
@ -35,4 +54,4 @@
</div> </div>
</metal:listing> </metal:listing>
</div> </div>
</metal:body> </metal:listing>

View file

@ -223,7 +223,7 @@ and register it
>>> personAdapter = regView.register(data) >>> personAdapter = regView.register(data)
>>> personAdapter.context.__name__, personAdapter.lastName, personAdapter.userId >>> 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: 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.formlib.namedtemplate import NamedTemplate
from zope.i18nmessageid import MessageFactory 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.node import NodeView
from loops.browser.concept import ConceptRelationView from loops.browser.concept import ConceptRelationView
from loops.organize.interfaces import ANNOTATION_KEY, IMemberRegistrationManager from loops.organize.interfaces import ANNOTATION_KEY, IMemberRegistrationManager
from loops.organize.interfaces import IMemberRegistration, raiseValidationError from loops.organize.interfaces import IMemberRegistration
_ = MessageFactory('zope') _ = MessageFactory('zope')
class MyConcepts(BaseView): class MyStuff(ConceptView):
template = NamedTemplate('loops.concept_macros')
@Lazy
def macro(self):
return self.template.macros['conceptlisting']
def __init__(self, context, request): def __init__(self, context, request):
self.context = context self.context = context
@ -59,23 +54,9 @@ class MyConcepts(BaseView):
if self.person is not None: if self.person is not None:
self.context = self.person self.context = self.person
def children(self): @Lazy
if self.person is None: def view(self):
return return self
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)
class PasswordWidget(BasePasswordWidget): class PasswordWidget(BasePasswordWidget):
@ -109,11 +90,13 @@ class MemberRegistration(Form, NodeView):
pw = form.get('password') pw = form.get('password')
if form.get('passwordConfirm') != pw: if form.get('passwordConfirm') != pw:
raise ValueError(u'Password and password confirmation do not match.') raise ValueError(u'Password and password confirmation do not match.')
login = form.get('loginName')
regMan = IMemberRegistrationManager(self.context.getLoopsRoot()) regMan = IMemberRegistrationManager(self.context.getLoopsRoot())
person = regMan.register(form.get('loginName'), pw, person = regMan.register(login, pw,
form.get('lastName'), form.get('lastName'),
form.get('firstName')) form.get('firstName'))
message = _(u'You have been registered and can now login.') 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 return person

View file

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

View file

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

View file

@ -39,6 +39,7 @@ from cybertools.typology.interfaces import IType
from loops.interfaces import ILoops from loops.interfaces import ILoops
from loops.concept import Concept from loops.concept import Concept
from loops.organize.interfaces import IMemberRegistrationManager from loops.organize.interfaces import IMemberRegistrationManager
from loops.organize.util import getPrincipalFolder, authPluginId
_ = MessageFactory('zope') _ = MessageFactory('zope')
@ -48,40 +49,32 @@ class MemberRegistrationManager(object):
implements(IMemberRegistrationManager) implements(IMemberRegistrationManager)
adapts(ILoops) adapts(ILoops)
authPluginId = 'loops'
def __init__(self, context): def __init__(self, context):
self.context = context self.context = context
def register(self, userId, password, lastName, firstName=u'', **kw): def register(self, userId, password, lastName, firstName=u'', **kw):
# step 1: create an internal principal in the loops principal folder: # step 1: create an internal principal in the loops principal folder:
pau = zapi.getUtility(IAuthentication, context=self.context) pFolder = getPrincipalFolder(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)
title = firstName and ' '.join((firstName, lastName)) or lastName title = firstName and ' '.join((firstName, lastName)) or lastName
# TODO: care for password encryption: # TODO: care for password encryption:
principal = InternalPrincipal(userId, password, title) principal = InternalPrincipal(userId, password, title)
pFolder[userId] = principal pFolder[userId] = principal
# step 2: create a corresponding person concept: # step 2: create a corresponding person concept:
cm = self.context.getConceptManager() cm = self.context.getConceptManager()
id = userId id = baseId = 'person.' + userId
num = 0 num = 0
while id in cm: while id in cm:
num +=1 num +=1
id = userId + str(num) id = baseId + str(num)
person = cm[id] = Concept(title) person = cm[id] = Concept(title)
# TODO: the name of the person type object must be kept flexible! # 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'] person.conceptType = cm['person']
personAdapter = IType(person).typeInterface(person) personAdapter = IType(person).typeInterface(person)
personAdapter.firstName = firstName personAdapter.firstName = firstName
personAdapter.lastName = lastName personAdapter.lastName = lastName
personAdapter.userId = '.'.join((self.authPluginId, userId)) personAdapter.userId = '.'.join((authPluginId, userId))
notify(ObjectCreatedEvent(person)) notify(ObjectCreatedEvent(person))
notify(ObjectModifiedEvent(person)) notify(ObjectModifiedEvent(person))
return personAdapter 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)