allow for adoption of relations to a predicate interface;

with example implementation for a 'has Role' predicate in loops.organize
This commit is contained in:
Helmut Merz 2011-09-23 09:39:32 +02:00
parent 2709f73f94
commit a8fce100fa
8 changed files with 111 additions and 29 deletions

View file

@ -6,6 +6,8 @@ $Id$
1.1
---
- allow for adoption of relations to a predicate interface;
with example implementation for a 'has Role' predicate in loops.organize
- external collection: provide functionality for automatically populate
meta information of media assets
- new query for retrieving work items independently of task or user

View file

@ -729,6 +729,12 @@ class IPredicate(IConceptSchema):
required=False)
class IRelationAdapter(Interface):
""" Base interface for adapters to relations that allow the specification
of special properties of a relation.
"""
# probably not useful
class xxIMappingAttributeRelation(IConceptSchema):
""" A relation based on a predicate ('mappingAttribute') that provides

View file

@ -390,15 +390,6 @@ Events listing
>>> list(listing.events())
[<loops.browser.concept.ConceptRelationView ...>]
Allocation of persons to tasks
------------------------------
>>> from loops.organize.interfaces import IAllocated
>>> predicate = concepts['predicate']
>>> allocated = addAndConfigureObject(concepts, Concept, 'allocated',
... title=u'allocated',
... conceptType=predicate, predicateInterface=IAllocated)
Send Email to Members
=====================
@ -423,6 +414,45 @@ Show Presence of Other Users
>>> component.provideUtility(Presence())
Roles of Persons
================
When persons are assigned to a parent (e.g. an instutution or a project)
this assignment may be characterized by a certain role. This role may
be specified by using a special predicate that is associated with a
predicate interface that allows to specify the role.
(Note that the security-relevant assignment of persons is managed via
other special predicates: 'ismember', 'ismaster'. The 'hasrole'
predicate described here is intended for situations where the roles
may be chosen from an arbitrary list.)
>>> from loops.organize.interfaces import IHasRole
>>> predicate = concepts['predicate']
>>> hasRole = addAndConfigureObject(concepts, Concept, 'hasrole',
... title=u'has Role',
... conceptType=predicate, predicateInterface=IHasRole)
Let's now assign john to task01 and have a look at the relation created.
>>> task01.assignChild(john, hasRole)
>>> relation = task01.getChildRelations([hasRole])[0]
The role may be accessed by getting a relation adapter
>>> from loops.predicate import adaptedRelation
>>> adRelation = adaptedRelation(relation)
>>> adRelation.role is None
True
>>> adRelation.role = 'member'
>>> relation._role
'member'
>>> adRelation = adaptedRelation(relation)
>>> adRelation.role
'member'
Calendar
========

View file

@ -39,6 +39,16 @@
set_schema="loops.organize.interfaces.ITask" />
</zope:class>
<zope:adapter factory="loops.organize.party.HasRole"
provides="loops.organize.interfaces.IHasRole"
trusted="True" />
<zope:class class="loops.organize.party.HasRole">
<require permission="zope.View"
interface="loops.organize.interfaces.IHasRole" />
<require permission="zope.ManageContent"
set_schema="loops.organize.interfaces.IHasRole" />
</zope:class>
<!-- member registration -->
<zope:adapter factory="loops.organize.member.MemberRegistrationManager"

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
# Copyright (c) 2011 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
@ -32,9 +32,8 @@ from zope.security.proxy import removeSecurityProxy
from cybertools.organize.interfaces import IAddress as IBaseAddress
from cybertools.organize.interfaces import IPerson as IBasePerson
from cybertools.organize.interfaces import ITask
from loops.interfaces import IConceptSchema
from loops.interfaces import ILoopsAdapter, IConceptSchema, IRelationAdapter
from loops.organize.util import getPrincipalFolder
from loops.interfaces import ILoopsAdapter
from loops import util
from loops.util import _
@ -164,19 +163,20 @@ class ITask(IConceptSchema, ITask, ILoopsAdapter):
pass
# 'allocated' predicate
# 'hasrole' predicate
class IAllocated(IConceptSchema):
class IHasRole(IRelationAdapter):
allocType = schema.Choice(
title=_(u'Allocation Type'),
role = schema.Choice(
title=_(u'Role'),
description=_(u'Specifies the kind of interaction a person or another '
u'party has with the task or project it is allocated to.'),
u'party has with an institution, a task, or a project '
u'it is associated with.'),
source=util.KeywordVocabulary((
('standard', _(u'Standard')),
('member', _(u'Member')),
('master', _(u'Master')),
)),
default='standard',
default='member',
required=True)

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
# Copyright (c) 2011 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
@ -40,8 +40,9 @@ from cybertools.typology.interfaces import IType
from loops.common import AdapterBase
from loops.concept import Concept
from loops.interfaces import IConcept
from loops.organize.interfaces import IAddress, IPerson, IAllocated
from loops.organize.interfaces import IAddress, IPerson, IHasRole
from loops.organize.interfaces import ANNOTATION_KEY
from loops.predicate import RelationAdapter
from loops.security.common import assignOwner, removeOwner, allowEditingForOwner
from loops.type import TypeInterfaceSourceList
from loops.predicate import PredicateInterfaceSourceList
@ -51,7 +52,7 @@ from loops import util
# register type interfaces - (TODO: use a function for this)
TypeInterfaceSourceList.typeInterfaces += (IPerson, IAddress)
PredicateInterfaceSourceList.typeInterfaces += (IAllocated,)
PredicateInterfaceSourceList.predicateInterfaces += (IHasRole,)
def getPersonForUser(context, request=None, principal=None):
@ -177,3 +178,11 @@ class Address(AdapterBase):
self.context._lines = value
lines = property(getLines, setLines)
class HasRole(RelationAdapter):
""" Allows specification of a role for a relation.
"""
implements(IHasRole)
_contextAttributes = list(IHasRole)

View file

@ -23,8 +23,8 @@ from zope.app.securitypolicy.interfaces import IPrincipalRoleManager
from cybertools.util.jeep import Jeep
from loops.common import adapted
from loops.concept import Concept
from loops.organize.interfaces import IPerson
from loops.organize.party import Person
from loops.organize.interfaces import IPerson, IHasRole
from loops.organize.party import Person, HasRole
from loops.organize.task import Task
from loops.setup import addAndConfigureObject
from loops.tests.auth import login
@ -38,6 +38,7 @@ def setupUtilitiesAndAdapters(loopsRoot):
component.provideAdapter(Person, provides=IPerson)
component.provideAdapter(Task)
component.provideAdapter(FoundPrincipalFactory)
component.provideAdapter(HasRole, provides=IHasRole)
return Jeep((
('auth', auth),
('principalAnnotations', principalAnnotations),

View file

@ -30,10 +30,10 @@ from zope.dottedname.resolve import resolve
from zope.security.proxy import removeSecurityProxy
from zope.traversing.api import getName
from loops.interfaces import ILoopsObject, IConcept, IResource
from loops.interfaces import IPredicate #, IMappingAttributeRelation
from loops.interfaces import ILoopsObject, IConcept, IResource, IConceptRelation
from loops.interfaces import IPredicate, IRelationAdapter #, IMappingAttributeRelation
from loops.concept import Concept
from loops.common import AdapterBase
from loops.common import adapted, AdapterBase
from loops.type import TypeInterfaceSourceList
@ -60,12 +60,36 @@ class PredicateInterfaceSourceList(TypeInterfaceSourceList):
may be used for specifying additional attributes of relations.
"""
typeInterfaces = ()
predicateInterfaces = ()
@property
def typeInterfaces(self):
return self.predicateInterfaces
class RelationAdapter(AdapterBase):
""" Base class for adapters to relations that may be used for
specifying additional attributes for relations.
"""
implements(IRelationAdapter)
adapts(IConceptRelation)
def adaptedRelation(relation):
if isinstance(relation, RelationAdapter):
return obj
ifc = adapted(relation.predicate).predicateInterface
if ifc is not None:
adRelation = component.queryAdapter(relation, ifc)
if adRelation is not None:
return adRelation
return relation
# standard relation adapters
#PredicateInterfaceSourceList.typeInterfaces += (IMappingAttributeRelation,)
#PredicateInterfaceSourceList.predicateInterfaces += (IMappingAttributeRelation,)
#class MappingAttributeRelation(AdapterBase):