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
|
||||
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():
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
/>
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
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