loops/organize
helmutm 33c8830b1c myconcepts: dynamic query for person
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1218 fd906abe-77d9-0310-91a1-e0d9ade77398
2006-05-19 10:59:54 +00:00
..
__init__.py work-in-progress: loops.organize: type 'person' implemented 2006-05-10 18:44:34 +00:00
browser.py myconcepts: dynamic query for person 2006-05-19 10:59:54 +00:00
configure.zcml myconcepts: dynamic query for person 2006-05-19 10:59:54 +00:00
interfaces.py more on the organize sub-package; set up query machinery for dynamically providing views 2006-05-19 09:34:03 +00:00
party.py more on the organize sub-package; set up query machinery for dynamically providing views 2006-05-19 09:34:03 +00:00
README.txt more on the organize sub-package; set up query machinery for dynamically providing views 2006-05-19 09:34:03 +00:00
tests.py work in progress: user management via IPerson adapters for concepts 2006-05-12 19:44:29 +00:00

===============================================================
loops - Linked Objects for Organization and Processing Services
===============================================================

  ($Id$)

Note: This packages depends on cybertools.organize.

Letz's do some basic set up

  >>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
  >>> site = placefulSetUp(True)
  
  >>> from zope import component, interface
  >>> from zope.app import zapi

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

  >>> loopsRoot = site['loops'] = Loops()

  >>> from cybertools.relation.interfaces import IRelationRegistry
  >>> from cybertools.relation.registry import DummyRelationRegistry
  >>> relations = DummyRelationRegistry()
  >>> component.provideUtility(relations, IRelationRegistry)

  >>> 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']

  >>> concepts['hasType'] = Concept(u'has type')
  >>> concepts['type'] = Concept(u'Type')
  >>> 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
  >>> johnC.conceptType = person


Organizations: Persons (and Users), Institutions, Addresses...
==============================================================

The classes used in this package are just adapters to IConcept.

  >>> from loops.organize.party import Person
  >>> component.provideAdapter(Person, (IConcept,), IPerson)

  >>> john = IPerson(johnC)
  >>> john.title
  u'John'
  >>> john.firstName = u'John'
  >>> johnC._firstName
  u'John'
  >>> john.lastName is None
  True
  >>> john.someOtherAttribute
  Traceback (most recent call last):
      ...
  AttributeError: someOtherAttribute

We can use the age calculations from the base Person class:

  >>> from datetime import date
  >>> john.birthDate = date(1980, 3, 26)
  >>> john.ageAt(date(2006, 5, 12))
  26
  >>> john.age >= 26
  True

A person can be associated with a user of the system by setting the
userId attribute; this will also register the person concept in the
corresponding principal annotations so that there is a fast way to find
the person(s) belonging to a user/principal.

For testing, we first have to provide the needed utilities and settings
(in real life this is all done during Zope startup):

  >>> from zope.app.security.interfaces import IAuthentication
  >>> from zope.app.security.principalregistry import PrincipalRegistry
  >>> auth = PrincipalRegistry()
  >>> component.provideUtility(auth, IAuthentication)
      
  >>> from zope.app.principalannotation.interfaces import IPrincipalAnnotationUtility
  >>> from zope.app.principalannotation import PrincipalAnnotationUtility
  >>> principalAnnotations = PrincipalAnnotationUtility()
  >>> component.provideUtility(principalAnnotations, IPrincipalAnnotationUtility)

  >>> principal = auth.definePrincipal('users.john', u'John', login='john')

  >>> john.userId = 'users.john'

  >>> annotations = principalAnnotations.getAnnotationsById('users.john')
  >>> from loops.organize.party import ANNOTATION_KEY
  >>> annotations.get(ANNOTATION_KEY) == johnC
  True

Change a userId assignment:

  >>> principal = auth.definePrincipal('users.johnny', u'Johnny', login='johnny')
  >>> john.userId = 'users.johnny'
      
  >>> annotations = principalAnnotations.getAnnotationsById('users.johnny')
  >>> annotations.get(ANNOTATION_KEY) == johnC
  True
  >>> annotations = principalAnnotations.getAnnotationsById('users.john')
  >>> annotations.get(ANNOTATION_KEY) is None
  True

  >>> john.userId = None
  >>> annotations = principalAnnotations.getAnnotationsById('users.johnny')
  >>> 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
=============

  >>> placefulTearDown()