loops.organize: handling of concept deletion, error checking

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1210 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-05-14 09:33:11 +00:00
parent 966a75f166
commit 60111065e7
3 changed files with 98 additions and 22 deletions

View file

@ -14,9 +14,14 @@ Letz's do some basic set up
>>> from zope import component, interface >>> from zope import component, interface
>>> from zope.app import zapi >>> from zope.app import zapi
and setup a simple loops site with a concept manager and some concepts: and setup a simple loops site with a concept manager and some concepts
(with all the type machinery, what in real life is done via standard
ZCML setup):
>>> from loops import Loops >>> from loops import Loops
>>> from loops.concept import ConceptManager, Concept
>>> from loops.interfaces import IConcept, ITypeConcept
>>> site['loops'] = Loops() >>> site['loops'] = Loops()
>>> loopsRoot = site['loops'] >>> loopsRoot = site['loops']
@ -25,7 +30,11 @@ and setup a simple loops site with a concept manager and some concepts:
>>> relations = DummyRelationRegistry() >>> relations = DummyRelationRegistry()
>>> component.provideUtility(relations, IRelationRegistry) >>> component.provideUtility(relations, IRelationRegistry)
>>> from loops.concept import ConceptManager, Concept >>> from cybertools.typology.interfaces import IType
>>> from loops.type import ConceptType, TypeConcept
>>> component.provideAdapter(ConceptType, (IConcept,), IType)
>>> component.provideAdapter(TypeConcept, (IConcept,), ITypeConcept)
>>> loopsRoot['concepts'] = ConceptManager() >>> loopsRoot['concepts'] = ConceptManager()
>>> concepts = loopsRoot['concepts'] >>> concepts = loopsRoot['concepts']
@ -34,9 +43,11 @@ and setup a simple loops site with a concept manager and some concepts:
>>> type = concepts['type'] >>> type = concepts['type']
>>> type.conceptType = type >>> type.conceptType = type
>>> from loops.organize.interfaces import IPerson
>>> concepts['person'] = Concept(u'Person') >>> concepts['person'] = Concept(u'Person')
>>> person = concepts['person'] >>> person = concepts['person']
>>> person.conceptType = type >>> person.conceptType = type
>>> ITypeConcept(person).typeInterface = IPerson
>>> johnC = Concept(u'John') >>> johnC = Concept(u'John')
>>> concepts['john'] = johnC >>> concepts['john'] = johnC
@ -48,8 +59,6 @@ Organizations: Persons (and Users), Institutions, Addresses...
The classes used in this package are just adapters to IConcept. The classes used in this package are just adapters to IConcept.
>>> from loops.interfaces import IConcept
>>> from loops.organize.interfaces import IPerson
>>> from loops.organize.party import Person >>> from loops.organize.party import Person
>>> component.provideAdapter(Person, (IConcept,), IPerson) >>> component.provideAdapter(Person, (IConcept,), IPerson)
@ -98,7 +107,8 @@ For testing, we first have to provide the needed utilities and settings
>>> john.userId = 'users.john' >>> john.userId = 'users.john'
>>> annotations = principalAnnotations.getAnnotationsById('users.john') >>> annotations = principalAnnotations.getAnnotationsById('users.john')
>>> annotations.get('loops.organize.person') == relations.getUniqueIdForObject(johnC) >>> from loops.organize.party import ANNOTATION_KEY
>>> annotations.get(ANNOTATION_KEY) == johnC
True True
Change a userId assignment: Change a userId assignment:
@ -107,20 +117,54 @@ Change a userId assignment:
>>> john.userId = 'users.johnny' >>> john.userId = 'users.johnny'
>>> annotations = principalAnnotations.getAnnotationsById('users.johnny') >>> annotations = principalAnnotations.getAnnotationsById('users.johnny')
>>> annotations.get('loops.organize.person') == relations.getUniqueIdForObject(johnC) >>> annotations.get(ANNOTATION_KEY) == johnC
True True
>>> annotations = principalAnnotations.getAnnotationsById('users.john') >>> annotations = principalAnnotations.getAnnotationsById('users.john')
>>> annotations.get('loops.organize.person') is None >>> annotations.get(ANNOTATION_KEY) is None
True True
>>> john.userId = None >>> john.userId = None
>>> annotations = principalAnnotations.getAnnotationsById('users.johnny') >>> annotations = principalAnnotations.getAnnotationsById('users.johnny')
>>> annotations.get('loops.organize.person') is None >>> annotations.get(ANNOTATION_KEY) is None
True True
Deleting a person with a userId assigned removes the corresponding Deleting a person with a userId assigned removes the corresponding
principal annotation: principal annotation:
>>> from zope.app.container.interfaces import IObjectRemovedEvent
>>> from zope.app.container.contained import ObjectRemovedEvent
>>> from zope.event import notify
>>> from zope.interface import Interface
>>> from loops.organize.party import removePersonReferenceFromPrincipal
>>> from zope.app.testing import ztapi
>>> ztapi.subscribe([IConcept, IObjectRemovedEvent], None,
... removePersonReferenceFromPrincipal)
>>> john.userId = 'users.john'
>>> annotations = principalAnnotations.getAnnotationsById('users.john')
>>> annotations.get(ANNOTATION_KEY) == johnC
True
>>> del concepts['john']
>>> annotations = principalAnnotations.getAnnotationsById('users.john')
>>> annotations.get(ANNOTATION_KEY) is None
True
If we try to assign a userId of a principal that already has a person
concept assigned we should get an error:
>>> john.userId = 'users.john'
>>> marthaC = Concept(u'Martha')
>>> concepts['martha'] = marthaC
>>> marthaC.conceptType = person
>>> martha = IPerson(marthaC)
>>> martha.userId = 'users.john'
Traceback (most recent call last):
...
ValueError: ...
Fin de partie Fin de partie
============= =============

View file

@ -19,4 +19,10 @@
set_schema="loops.organize.interfaces.IPerson" /> set_schema="loops.organize.interfaces.IPerson" />
</zope:class> </zope:class>
<zope:subscriber
for="loops.interfaces.IConcept
zope.app.container.interfaces.IObjectRemovedEvent"
handler="loops.organize.party.removePersonReferenceFromPrincipal"
/>
</configure> </configure>

View file

@ -31,12 +31,14 @@ from zope.interface import implements
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from zope.security.proxy import removeSecurityProxy from zope.security.proxy import removeSecurityProxy
#from cybertools.organize.interfaces import IPerson
from cybertools.organize.party import Person as BasePerson from cybertools.organize.party import Person as BasePerson
from cybertools.relation.interfaces import IRelationRegistry from cybertools.typology.interfaces import IType
from loops.interfaces import IConcept from loops.interfaces import IConcept
from loops.type import TypeInterfaceSourceList
from loops.organize.interfaces import IPerson from loops.organize.interfaces import IPerson
from loops.type import TypeInterfaceSourceList
ANNOTATION_KEY = 'loops.organize.person'
# register IPerson as a type interface - (TODO: use a function for this) # register IPerson as a type interface - (TODO: use a function for this)
@ -52,6 +54,7 @@ class Person(BasePerson):
adapts(IConcept) adapts(IConcept)
__attributes = ('context', '__parent__', 'userId',) __attributes = ('context', '__parent__', 'userId',)
__schemas = list(IPerson) + list(IConcept)
def __init__(self, context): def __init__(self, context):
self.context = context # to get the permission stuff right self.context = context # to get the permission stuff right
@ -69,31 +72,37 @@ class Person(BasePerson):
setattr(self.context, '_' + attr, value) setattr(self.context, '_' + attr, value)
def checkAttr(self, attr): def checkAttr(self, attr):
if attr not in list(IPerson) + list(IConcept): if attr not in self.__schemas:
raise AttributeError(attr) raise AttributeError(attr)
def getUserId(self): def getUserId(self):
return getattr(self.context, '_userId', None) return getattr(self.context, '_userId', None)
def setUserId(self, userId): def setUserId(self, userId):
auth = self.authentication auth = self.authentication
oldUserId = self.userId
if oldUserId and oldUserId != userId:
principal = self.getPrincipalForUserId(oldUserId)
if principal is not None:
pa = annotations(principal)
pa['loops.organize.person'] = None
if userId: if userId:
principal = auth.getPrincipal(userId) principal = auth.getPrincipal(userId)
pa = annotations(principal) pa = annotations(principal)
relations = component.getUtility(IRelationRegistry) person = pa.get(ANNOTATION_KEY, None)
uid = relations.getUniqueIdForObject(self.context) if person is not None and person != self.context:
pa['loops.organize.person'] = uid raise ValueError(
'There is alread a person (%s) assigned to user %s.'
% (zapi.getName(person), userId))
pa[ANNOTATION_KEY] = self.context
oldUserId = self.userId
if oldUserId and oldUserId != userId:
self.removeReferenceFromPrincipal(oldUserId)
self.context._userId = userId self.context._userId = userId
userId = property(getUserId, setUserId) userId = property(getUserId, setUserId)
def removeReferenceFromPrincipal(self, userId):
principal = self.getPrincipalForUserId(userId)
if principal is not None:
pa = annotations(principal)
pa[ANNOTATION_KEY] = None
@Lazy @Lazy
def authentication(self): def authentication(self):
return component.getUtility(IAuthentication, context=self.context) return getAuthenticationUtility(self.context)
@Lazy @Lazy
def principal(self): def principal(self):
@ -110,3 +119,20 @@ class Person(BasePerson):
return None return None
def getAuthenticationUtility(context):
return component.getUtility(IAuthentication, context=context)
def removePersonReferenceFromPrincipal(context, event):
""" Handles IObjectRemoved event for concepts used as persons.
"""
if IConcept.providedBy(context):
# this does not work as the context is already removed from the
# relation registry:
#if IType(context).typeInterface == IPerson:
# person = IPerson(context)
# if person.userId:
if getattr(context, '_userId', None):
person = IPerson(context)
person.removeReferenceFromPrincipal(person.userId)