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:
parent
00e27595ca
commit
6ab11a50e9
8 changed files with 110 additions and 52 deletions
|
@ -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():
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
44
organize/util.py
Normal 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)
|
||||||
|
|
Loading…
Add table
Reference in a new issue