work in progress: user management via IPerson adapters for concepts
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1208 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
b79666d1b5
commit
966a75f166
5 changed files with 240 additions and 24 deletions
129
organize/README.txt
Normal file
129
organize/README.txt
Normal file
|
@ -0,0 +1,129 @@
|
|||
===============================================================
|
||||
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:
|
||||
|
||||
>>> from loops import Loops
|
||||
>>> site['loops'] = Loops()
|
||||
>>> loopsRoot = site['loops']
|
||||
|
||||
>>> from cybertools.relation.interfaces import IRelationRegistry
|
||||
>>> from cybertools.relation.registry import DummyRelationRegistry
|
||||
>>> relations = DummyRelationRegistry()
|
||||
>>> component.provideUtility(relations, IRelationRegistry)
|
||||
|
||||
>>> from loops.concept import ConceptManager, Concept
|
||||
>>> loopsRoot['concepts'] = ConceptManager()
|
||||
>>> concepts = loopsRoot['concepts']
|
||||
|
||||
>>> concepts['hasType'] = Concept(u'has type')
|
||||
>>> concepts['type'] = Concept(u'Type')
|
||||
>>> type = concepts['type']
|
||||
>>> type.conceptType = type
|
||||
|
||||
>>> concepts['person'] = Concept(u'Person')
|
||||
>>> person = concepts['person']
|
||||
>>> person.conceptType = type
|
||||
|
||||
>>> 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.interfaces import IConcept
|
||||
>>> from loops.organize.interfaces import IPerson
|
||||
>>> 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')
|
||||
>>> annotations.get('loops.organize.person') == relations.getUniqueIdForObject(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('loops.organize.person') == relations.getUniqueIdForObject(johnC)
|
||||
True
|
||||
>>> annotations = principalAnnotations.getAnnotationsById('users.john')
|
||||
>>> annotations.get('loops.organize.person') is None
|
||||
True
|
||||
|
||||
>>> john.userId = None
|
||||
>>> annotations = principalAnnotations.getAnnotationsById('users.johnny')
|
||||
>>> annotations.get('loops.organize.person') is None
|
||||
True
|
||||
|
||||
Deleting a person with a userId assigned removes the corresponding
|
||||
principal annotation:
|
||||
|
||||
|
||||
Fin de partie
|
||||
=============
|
||||
|
||||
>>> placefulTearDown()
|
||||
|
|
@ -9,13 +9,14 @@
|
|||
<!-- adapters -->
|
||||
|
||||
<zope:adapter factory="loops.organize.party.Person"
|
||||
provides="loops.organize.interfaces.IPerson"
|
||||
trusted="True" />
|
||||
|
||||
<zope:class class="loops.organize.party.Person">
|
||||
<require permission="zope.View"
|
||||
interface="cybertools.organize.interfaces.IPerson" />
|
||||
interface="loops.organize.interfaces.IPerson" />
|
||||
<require permission="zope.ManageContent"
|
||||
set_schema="cybertools.organize.interfaces.IPerson" />
|
||||
set_schema="loops.organize.interfaces.IPerson" />
|
||||
</zope:class>
|
||||
|
||||
</configure>
|
||||
|
|
44
organize/interfaces.py
Normal file
44
organize/interfaces.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
|
||||
#
|
||||
|
||||
"""
|
||||
Interfaces for organizational stuff like persons and addresses.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.interface import Interface, Attribute
|
||||
from zope import schema
|
||||
from zope.i18nmessageid import MessageFactory
|
||||
from cybertools.organize.interfaces import IPerson as IBasePerson
|
||||
|
||||
_ = MessageFactory('zope')
|
||||
|
||||
|
||||
class IPerson(IBasePerson):
|
||||
""" Resembles a human being with a name (first and last name),
|
||||
a birth date, and a set of addresses. This interface only
|
||||
lists fields used in addidtion to those provided by the
|
||||
basic cybertools.organize package.
|
||||
"""
|
||||
|
||||
userId = schema.TextLine(
|
||||
title=_(u'User ID'),
|
||||
description=_(u'The principal id of a user that should '
|
||||
'be associated with this person.'),
|
||||
required=False,)
|
|
@ -22,48 +22,91 @@ Adapters for IConcept providing interfaces from the cybertools.organize package.
|
|||
$Id$
|
||||
"""
|
||||
|
||||
from zope import interface, component
|
||||
from zope.app import zapi
|
||||
from zope.app.principalannotation import annotations
|
||||
from zope.app.security.interfaces import IAuthentication, PrincipalLookupError
|
||||
from zope.component import adapts
|
||||
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.interfaces import IPerson
|
||||
from cybertools.organize.party import Person as BasePerson
|
||||
from cybertools.relation.interfaces import IRelationRegistry
|
||||
from loops.interfaces import IConcept
|
||||
from loops.type import TypeInterfaceSourceList
|
||||
from loops.organize.interfaces import IPerson
|
||||
|
||||
|
||||
# register IPerson as a type interface - (TODO: use a function for this)
|
||||
|
||||
TypeInterfaceSourceList.typeInterfaces += (IPerson,)
|
||||
|
||||
|
||||
class Person(object):
|
||||
class Person(BasePerson):
|
||||
""" typeInterface adapter for concepts of type 'person'.
|
||||
"""
|
||||
|
||||
implements(IPerson)
|
||||
adapts(IConcept)
|
||||
|
||||
__attributes = ('context', '__parent__', 'userId',)
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
self.__parent__ = context # to get the permission stuff right
|
||||
self.context = context # to get the permission stuff right
|
||||
self.__parent__ = context
|
||||
|
||||
def getFirstName(self):
|
||||
return getattr(self.context, '_firstName', u'')
|
||||
def setFirstName(self, firstName):
|
||||
self.context._firstName = firstName
|
||||
firstName = property(getFirstName, setFirstName)
|
||||
def __getattr__(self, attr):
|
||||
self.checkAttr(attr)
|
||||
return getattr(self.context, '_' + attr, None)
|
||||
|
||||
def getLastName(self):
|
||||
return getattr(self.context, '_lastName', u'')
|
||||
def setLastName(self, lastName):
|
||||
self.context._lastName = lastName
|
||||
lastName = property(getLastName, setLastName)
|
||||
|
||||
def getBirthDate(self):
|
||||
return getattr(self.context, '_birthDate', u'')
|
||||
def setBirthDate(self, birthDate):
|
||||
self.context._birthDate = birthDate
|
||||
birthDate = property(getBirthDate, setBirthDate)
|
||||
def __setattr__(self, attr, value):
|
||||
if attr in self.__attributes:
|
||||
object.__setattr__(self, attr, value)
|
||||
else:
|
||||
self.checkAttr(attr)
|
||||
setattr(self.context, '_' + attr, value)
|
||||
|
||||
def checkAttr(self, attr):
|
||||
if attr not in list(IPerson) + list(IConcept):
|
||||
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
|
||||
self.context._userId = userId
|
||||
userId = property(getUserId, setUserId)
|
||||
|
||||
@Lazy
|
||||
def authentication(self):
|
||||
return component.getUtility(IAuthentication, context=self.context)
|
||||
|
||||
@Lazy
|
||||
def principal(self):
|
||||
return self.getPrincipalForUserId()
|
||||
|
||||
def getPrincipalForUserId(self, userId=None):
|
||||
userId = userId or self.userId
|
||||
if not userId:
|
||||
return None
|
||||
auth = self.authentication
|
||||
try:
|
||||
return auth.getPrincipal(userId)
|
||||
except PrincipalLookupError:
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
@ -17,8 +17,7 @@ def test_suite():
|
|||
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
|
||||
return unittest.TestSuite((
|
||||
unittest.makeSuite(Test),
|
||||
#DocFileSuite('../README.txt', optionflags=flags),
|
||||
#DocFileSuite('../helpers.txt', optionflags=flags),
|
||||
DocFileSuite('README.txt', optionflags=flags),
|
||||
))
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Add table
Reference in a new issue