From 60111065e772da54dc1c78f23cd03ee4c64b7b88 Mon Sep 17 00:00:00 2001 From: helmutm Date: Sun, 14 May 2006 09:33:11 +0000 Subject: [PATCH] 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 --- organize/README.txt | 60 +++++++++++++++++++++++++++++++++++------ organize/configure.zcml | 6 +++++ organize/party.py | 54 +++++++++++++++++++++++++++---------- 3 files changed, 98 insertions(+), 22 deletions(-) diff --git a/organize/README.txt b/organize/README.txt index a0872c6..8df35df 100644 --- a/organize/README.txt +++ b/organize/README.txt @@ -14,9 +14,14 @@ Letz's do some basic set up >>> from zope import component, interface >>> 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.concept import ConceptManager, Concept + >>> from loops.interfaces import IConcept, ITypeConcept + >>> site['loops'] = Loops() >>> loopsRoot = site['loops'] @@ -25,7 +30,11 @@ and setup a simple loops site with a concept manager and some concepts: >>> relations = DummyRelationRegistry() >>> 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() >>> concepts = loopsRoot['concepts'] @@ -34,9 +43,11 @@ and setup a simple loops site with a concept manager and some concepts: >>> type = concepts['type'] >>> type.conceptType = type + >>> from loops.organize.interfaces import IPerson >>> concepts['person'] = Concept(u'Person') >>> person = concepts['person'] >>> person.conceptType = type + >>> ITypeConcept(person).typeInterface = IPerson >>> johnC = Concept(u'John') >>> concepts['john'] = johnC @@ -48,8 +59,6 @@ Organizations: Persons (and Users), Institutions, Addresses... 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 >>> 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' >>> 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 Change a userId assignment: @@ -107,20 +117,54 @@ Change a userId assignment: >>> john.userId = 'users.johnny' >>> annotations = principalAnnotations.getAnnotationsById('users.johnny') - >>> annotations.get('loops.organize.person') == relations.getUniqueIdForObject(johnC) + >>> annotations.get(ANNOTATION_KEY) == johnC True >>> annotations = principalAnnotations.getAnnotationsById('users.john') - >>> annotations.get('loops.organize.person') is None + >>> annotations.get(ANNOTATION_KEY) is None True >>> john.userId = None >>> annotations = principalAnnotations.getAnnotationsById('users.johnny') - >>> annotations.get('loops.organize.person') is None + >>> annotations.get(ANNOTATION_KEY) is None True Deleting a person with a userId assigned removes the corresponding 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 ============= diff --git a/organize/configure.zcml b/organize/configure.zcml index e975e8e..0e7d007 100644 --- a/organize/configure.zcml +++ b/organize/configure.zcml @@ -19,4 +19,10 @@ set_schema="loops.organize.interfaces.IPerson" /> + + diff --git a/organize/party.py b/organize/party.py index a50c124..ab50a1c 100644 --- a/organize/party.py +++ b/organize/party.py @@ -31,12 +31,14 @@ from zope.interface import implements from zope.cachedescriptors.property import Lazy from zope.security.proxy import removeSecurityProxy -#from cybertools.organize.interfaces import IPerson 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.type import TypeInterfaceSourceList 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) @@ -52,6 +54,7 @@ class Person(BasePerson): adapts(IConcept) __attributes = ('context', '__parent__', 'userId',) + __schemas = list(IPerson) + list(IConcept) def __init__(self, context): self.context = context # to get the permission stuff right @@ -69,31 +72,37 @@ class Person(BasePerson): setattr(self.context, '_' + attr, value) def checkAttr(self, attr): - if attr not in list(IPerson) + list(IConcept): + if attr not in self.__schemas: raise AttributeError(attr) def getUserId(self): return getattr(self.context, '_userId', None) def setUserId(self, userId): 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: principal = auth.getPrincipal(userId) pa = annotations(principal) - relations = component.getUtility(IRelationRegistry) - uid = relations.getUniqueIdForObject(self.context) - pa['loops.organize.person'] = uid + person = pa.get(ANNOTATION_KEY, None) + if person is not None and person != self.context: + 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 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 def authentication(self): - return component.getUtility(IAuthentication, context=self.context) + return getAuthenticationUtility(self.context) @Lazy def principal(self): @@ -110,3 +119,20 @@ class Person(BasePerson): 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) +