Assignment of resources to concepts and vice versa

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1108 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-03-04 14:50:16 +00:00
parent fc6946be95
commit d6b7f5bc1f
10 changed files with 410 additions and 47 deletions

View file

@ -121,7 +121,7 @@ a special concept type.
Concept Views Concept Views
------------- -------------
>>> from loops.browser.concept import ConceptView >>> from loops.browser.concept import ConceptView, ConceptConfigureView
>>> view = ConceptView(cc1, TestRequest()) >>> view = ConceptView(cc1, TestRequest())
>>> children = list(view.children()) >>> children = list(view.children())
@ -136,18 +136,19 @@ of URIs to item and the predicate of the relationship:
>>> [c.token for c in children] >>> [c.token for c in children]
['.loops/concepts/cc2:.loops/concepts/standard'] ['.loops/concepts/cc2:.loops/concepts/standard']
The concept view allows updating the underlying context object: There is also a concept configuration view that allows updating the
underlying context object:
>>> cc3 = Concept(u'loops for Zope 3') >>> cc3 = Concept(u'loops for Zope 3')
>>> concepts['cc3'] = cc3 >>> concepts['cc3'] = cc3
>>> view = ConceptView(cc1, >>> view = ConceptConfigureView(cc1,
... TestRequest(action='assign', tokens=['.loops/concepts/cc3'])) ... TestRequest(action='assign', tokens=['.loops/concepts/cc3']))
>>> view.update() >>> view.update()
True True
>>> sorted(c.title for c in cc1.getChildren()) >>> sorted(c.title for c in cc1.getChildren())
[u'Zope 3', u'loops for Zope 3'] [u'Zope 3', u'loops for Zope 3']
>>> view = ConceptView(cc1, >>> view = ConceptConfigureView(cc1,
... TestRequest(action='remove', qualifier='children', ... TestRequest(action='remove', qualifier='children',
... tokens=['.loops/concepts/cc2:.loops/concepts/standard'])) ... tokens=['.loops/concepts/cc2:.loops/concepts/standard']))
>>> view.update() >>> view.update()
@ -159,14 +160,14 @@ We can also create a new concept and assign it:
>>> params = {'action': 'create', 'create.name': 'cc4', >>> params = {'action': 'create', 'create.name': 'cc4',
... 'create.title': u'New concept'} ... 'create.title': u'New concept'}
>>> view = ConceptView(cc1, TestRequest(**params)) >>> view = ConceptConfigureView(cc1, TestRequest(**params))
>>> view.update() >>> view.update()
True True
>>> sorted(c.title for c in cc1.getChildren()) >>> sorted(c.title for c in cc1.getChildren())
[u'New concept', u'loops for Zope 3'] [u'New concept', u'loops for Zope 3']
The concept view provides methods for displaying concept types and The concept configuration view provides methods for displaying concept
predicates: types and predicates:
>>> from zope.publisher.interfaces.browser import IBrowserRequest >>> from zope.publisher.interfaces.browser import IBrowserRequest
>>> from loops.browser.common import LoopsTerms >>> from loops.browser.common import LoopsTerms
@ -257,14 +258,32 @@ We can associate a resource with a concept by assigning it to the concept:
>>> list(res) >>> list(res)
[<loops.resource.Document ...>] [<loops.resource.Document ...>]
The resource also provides access to the associated concepts (or views, see The concept configuration view discussed above also manages the relations
below) via the getClients() method: from concepts to resources:
>>> conc = doc1.getClients() >>> len(cc1.getResources())
>>> len(conc)
1 1
>>> conc[0] is cc1 >>> form = dict(action='remove', qualifier='resources',
... tokens=['.loops/resources/doc1:.loops/concepts/standard'])
>>> view = ConceptConfigureView(cc1, TestRequest(form=form))
>>> [zapi.getName(r.context) for r in view.resources()]
[u'doc1']
>>> view.update()
True True
>>> len(cc1.getResources())
0
>>> form = dict(action='assign', assignAs='resource',
... tokens=['.loops/resources/doc1'])
>>> view = ConceptConfigureView(cc1, TestRequest(form=form))
>>> view.update()
True
>>> len(cc1.getResources())
1
These relations may also be managed starting from a resource using
the resource configuration view:
>>> from loops.browser.resource import ResourceConfigureView
Index attributes adapter Index attributes adapter
------------------------ ------------------------
@ -393,6 +412,16 @@ out - this is usually done through ZCML.)
>>> m111.target is cc2 >>> m111.target is cc2
True True
A resource provides access to the associated views/nodes via the
getClients() method:
>>> len(doc1.getClients())
0
>>> m112.target = doc1
>>> nodes = doc1.getClients()
>>> nodes[0] is m112
True
Node Views Node Views
---------- ----------

View file

@ -28,6 +28,7 @@ from zope.app.dublincore.interfaces import ICMFDublinCore
from zope.app.event.objectevent import ObjectCreatedEvent from zope.app.event.objectevent import ObjectCreatedEvent
from zope.app.form.browser.interfaces import ITerms from zope.app.form.browser.interfaces import ITerms
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from zope.dottedname.resolve import resolve
from zope.event import notify from zope.event import notify
from zope.interface import implements from zope.interface import implements
from zope.publisher.interfaces import BadRequest from zope.publisher.interfaces import BadRequest
@ -35,7 +36,10 @@ from zope.publisher.interfaces.browser import IBrowserRequest
from zope import schema from zope import schema
from zope.schema.interfaces import IIterableSource from zope.schema.interfaces import IIterableSource
from zope.security.proxy import removeSecurityProxy from zope.security.proxy import removeSecurityProxy
from loops.interfaces import IConcept
from loops.concept import Concept, ConceptTypeSourceList, PredicateSourceList from loops.concept import Concept, ConceptTypeSourceList, PredicateSourceList
from loops.resource import getResourceTypes, getResourceTypesForSearch
from loops.target import getTargetTypes
from loops.browser.common import BaseView, LoopsTerms from loops.browser.common import BaseView, LoopsTerms
from loops import util from loops import util
@ -50,6 +54,13 @@ class ConceptView(BaseView):
for r in self.context.getParentRelations(): for r in self.context.getParentRelations():
yield ConceptRelationView(r, self.request) yield ConceptRelationView(r, self.request)
def resources(self):
for r in self.context.getResourceRelations():
yield ConceptResourceRelationView(r, self.request, contextIsSecond=True)
class ConceptConfigureView(ConceptView):
def update(self): def update(self):
request = self.request request = self.request
action = request.get('action') action = request.get('action')
@ -75,6 +86,8 @@ class ConceptView(BaseView):
self.context.assignChild(removeSecurityProxy(concept), predicate) self.context.assignChild(removeSecurityProxy(concept), predicate)
elif assignAs == 'parent': elif assignAs == 'parent':
self.context.assignParent(removeSecurityProxy(concept), predicate) self.context.assignParent(removeSecurityProxy(concept), predicate)
elif assignAs == 'resource':
self.context.assignResource(removeSecurityProxy(concept), predicate)
else: else:
raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs) raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs)
elif action == 'remove': elif action == 'remove':
@ -84,6 +97,8 @@ class ConceptView(BaseView):
self.context.deassignParent(concept, [predicate]) self.context.deassignParent(concept, [predicate])
elif qualifier == 'children': elif qualifier == 'children':
self.context.deassignChild(concept, [predicate]) self.context.deassignChild(concept, [predicate])
elif qualifier == 'resources':
self.context.deassignResource(concept, [predicate])
else: else:
raise(BadRequest, 'Illegal qualifier: %s.' % qualifier) raise(BadRequest, 'Illegal qualifier: %s.' % qualifier)
else: else:
@ -97,6 +112,11 @@ class ConceptView(BaseView):
raise(BadRequest, 'Empty name.') raise(BadRequest, 'Empty name.')
title = request.get('create.title', u'') title = request.get('create.title', u'')
conceptType = request.get('create.type') conceptType = request.get('create.type')
if conceptType and conceptType.startswith('loops.resource.'):
factory = resolve(conceptType)
concept = factory(title)
container = self.loopsRoot.getResourceManager()
else:
concept = Concept(title) concept = Concept(title)
container = self.loopsRoot.getConceptManager() container = self.loopsRoot.getConceptManager()
container[name] = concept container[name] = concept
@ -113,6 +133,8 @@ class ConceptView(BaseView):
self.context.assignChild(removeSecurityProxy(concept), predicate) self.context.assignChild(removeSecurityProxy(concept), predicate)
elif assignAs == 'parent': elif assignAs == 'parent':
self.context.assignParent(removeSecurityProxy(concept), predicate) self.context.assignParent(removeSecurityProxy(concept), predicate)
elif assignAs == 'resource':
self.context.assignResource(removeSecurityProxy(concept), predicate)
else: else:
raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs) raise(BadRequest, 'Illegal assignAs parameter: %s.' % assignAs)
@ -153,7 +175,10 @@ class ConceptView(BaseView):
def viewIterator(self, objs): def viewIterator(self, objs):
request = self.request request = self.request
for o in objs: for o in objs:
yield ConceptView(o, request) if IConcept.providedBy(o):
yield ConceptConfigureView(o, request)
else:
yield BaseView(o, request)
def conceptTypes(self): def conceptTypes(self):
types = ConceptTypeSourceList(self.context) types = ConceptTypeSourceList(self.context)
@ -171,6 +196,13 @@ class ConceptView(BaseView):
def getConceptTypeTokenForSearch(self, ct): def getConceptTypeTokenForSearch(self, ct):
return ct is None and 'unknown' or zapi.getName(ct) return ct is None and 'unknown' or zapi.getName(ct)
def resourceTypes(self):
return util.KeywordVocabulary(getResourceTypes())
def resourceTypesForSearch(self):
return util.KeywordVocabulary(getResourceTypesForSearch())
def predicates(self): def predicates(self):
preds = PredicateSourceList(self.context) preds = PredicateSourceList(self.context)
terms = zapi.getMultiAdapter((preds, self.request), ITerms) terms = zapi.getMultiAdapter((preds, self.request), ITerms)
@ -188,7 +220,6 @@ class ConceptRelationView(object):
self.context = relation.first self.context = relation.first
self.other = relation.second self.other = relation.second
self.predicate = relation.predicate self.predicate = relation.predicate
self.conceptType = self.context.conceptType
self.request = request self.request = request
@Lazy @Lazy
@ -208,6 +239,10 @@ class ConceptRelationView(object):
return ':'.join((self.loopsRoot.getLoopsUri(self.context), return ':'.join((self.loopsRoot.getLoopsUri(self.context),
self.loopsRoot.getLoopsUri(self.predicate))) self.loopsRoot.getLoopsUri(self.predicate)))
@Lazy
def conceptType(self):
return self.context.conceptType
@Lazy @Lazy
def typeTitle(self): def typeTitle(self):
return self.conceptType.title return self.conceptType.title
@ -224,3 +259,23 @@ class ConceptRelationView(object):
def predicateUrl(self): def predicateUrl(self):
return zapi.absoluteURL(self.predicate, self.request) return zapi.absoluteURL(self.predicate, self.request)
class ConceptResourceRelationView(ConceptRelationView):
@Lazy
def conceptType(self):
return None
@Lazy
def typeTitle(self):
voc = util.KeywordVocabulary(getTargetTypes())
token = '.'.join((self.context.__module__,
self.context.__class__.__name__))
term = voc.getTermByToken(token)
return term.title
@Lazy
def typeUrl(self):
return ''

View file

@ -0,0 +1,87 @@
<tal:tag condition="view/update" />
<html metal:use-macro="context/@@standard_macros/view"
i18n:domain="loops">
<body>
<div metal:fill-slot="body">
<h1 tal:content="context/title">Concept Title</h1><br />
<div tal:define="items view/resources;
action string:remove;
qualifier string:parents;
summary string:Currently assigned resources;
legend string:Resources;
showPredicate string:yes;
buttonText string:Remove Resources;"
style="float:left; padding-right:20px">
<metal:parents use-macro="views/relation_macros/listing" />
</div>
<div tal:define="legend string:Create Resource;
buttonText string:Create Resource"
style="padding-right:20px; clear:left">
<metal:create use-macro="views/relation_macros/create">
<select name="create.type" metal:fill-slot="types">
<tal:types repeat="type view/resourceTypes">
<option value="loops.resource.Document"
i18n:translate=""
tal:attributes="value type/token"
tal:content="type/title">Document</option>
</tal:types>
</select>
<metal:control fill-slot="control">
<input class="context" type="submit" name="form.button.submit"
value="Create Object"
i18n:attributes="value"
tal:attributes="value buttonText" />
<input type="hidden" name="assignAs" value="resource" />
and assign using Predicate
<select metal:use-macro="views/relation_macros/predicates" />
</metal:control>
</metal:create>
</div>
<div tal:define="items view/search;
action string:assign;
qualifier nothing;
summary string:Assignment candidates;
legend string:Search;
showPredicate nothing;
buttonText string:Assign;"
style="padding-right:20px">
<metal:assign use-macro="views/relation_macros/listing">
<metal:search fill-slot="topActions">
<metal:block use-macro="views/relation_macros/search">
<select name="searchType" metal:fill-slot="types">
<option value="loops:resource:*"
tal:attributes="selected python:
searchType == 'loops:resource:*'">Any</option>
<tal:types repeat="type view/resourceTypesForSearch">
<option value="loops:resource:Document"
i18n:translate=""
tal:attributes="value type/token;
selected python: type.token == searchType"
tal:content="type/title">Topic</option>
</tal:types>
</select>
</metal:block>
</metal:search>
<metal:special fill-slot="specialButtons">
<input type="hidden" name="assignAs" value="resource" />
Object(s) using Predicate
<select name="predicate">
<tal:types repeat="pred view/predicates">
<option value=".loops/concepts/hasType"
i18n:translate=""
tal:attributes="value pred/token"
tal:content="pred/title">Predicate</option>
</tal:types>
</select>
</metal:special>
</metal:assign>
</div>
</div>
</body>
</html>

View file

@ -105,7 +105,7 @@
<pages <pages
for="loops.interfaces.IConcept" for="loops.interfaces.IConcept"
class=".concept.ConceptView" class=".concept.ConceptConfigureView"
permission="zope.ManageContent"> permission="zope.ManageContent">
<page <page
@ -114,6 +114,12 @@
menu="zmi_views" title="Related Concepts" menu="zmi_views" title="Related Concepts"
/> />
<page
name="resources.html"
template="concept_resources.pt"
menu="zmi_views" title="Resources"
/>
</pages> </pages>
<editform <editform
@ -163,6 +169,21 @@
add="zope.ManageContent" add="zope.ManageContent"
/> />
<!-- resource in general -->
<pages
for="loops.interfaces.IResource"
class=".resource.ResourceConfigureView"
permission="zope.ManageContent">
<page
name="concepts.html"
template="resource_concepts.pt"
menu="zmi_views" title="Concepts"
/>
</pages>
<!-- document --> <!-- document -->
<!--<zope:view <!--<zope:view

View file

@ -43,6 +43,7 @@
<td> <td>
<a tal:condition="item/typeTitle | nothing" <a tal:condition="item/typeTitle | nothing"
tal:content="item/typeTitle" href="#" tal:content="item/typeTitle" href="#"
tal:omit-tag="not:item/typeUrl"
tal:attributes="href tal:attributes="href
string:${item/typeUrl}/@@SelectedManagementView.html"> string:${item/typeUrl}/@@SelectedManagementView.html">
Type Type
@ -85,7 +86,7 @@
<input name="create.title" size="30" <input name="create.title" size="30"
tal:attributes="value nothing" />&nbsp; tal:attributes="value nothing" />&nbsp;
<span i18n:translate="">Type</span> <span i18n:translate="">Type</span>
<select name="create.type"> <select name="create.type" metal:define-slot="types">
<tal:types repeat="type view/conceptTypes"> <tal:types repeat="type view/conceptTypes">
<option value=".loops/concepts/topic" <option value=".loops/concepts/topic"
i18n:translate="" i18n:translate=""
@ -96,6 +97,7 @@
</select> </select>
</div><br /> </div><br />
<div class="formControls"> <div class="formControls">
<metal:control define-slot="control">
<input class="context" type="submit" name="form.button.submit" <input class="context" type="submit" name="form.button.submit"
value="Create Object" value="Create Object"
i18n:attributes="value" i18n:attributes="value"
@ -106,7 +108,7 @@
<option value="parent" i18n:translate="">Parent</option> <option value="parent" i18n:translate="">Parent</option>
</select> </select>
using Predicate using Predicate
<select name="create.predicate"> <select name="create.predicate" metal:define-macro="predicates">
<tal:types repeat="pred view/predicates"> <tal:types repeat="pred view/predicates">
<option value=".loops/concepts/hasType" <option value=".loops/concepts/hasType"
i18n:translate="" i18n:translate=""
@ -114,6 +116,7 @@
tal:content="pred/title">Predicate</option> tal:content="pred/title">Predicate</option>
</tal:types> </tal:types>
</select> </select>
</metal:control>
</div> </div>
</form> </form>
</fieldset> </fieldset>
@ -131,7 +134,7 @@
<input name="searchTerm" <input name="searchTerm"
tal:attributes="value searchTerm" /> tal:attributes="value searchTerm" />
<span i18n:translate="">Type</span> <span i18n:translate="">Type</span>
<select name="searchType"> <select name="searchType" metal:define-slot="types">
<option value="loops:concept:*" <option value="loops:concept:*"
tal:attributes="selected python: tal:attributes="selected python:
searchType == 'loops:concept:*'">Any</option> searchType == 'loops:concept:*'">Any</option>

View file

@ -24,12 +24,15 @@ $Id$
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from zope.app import zapi from zope.app import zapi
from zope.app.catalog.interfaces import ICatalog
from zope.app.dublincore.interfaces import ICMFDublinCore from zope.app.dublincore.interfaces import ICMFDublinCore
from zope.proxy import removeAllProxies from zope.proxy import removeAllProxies
from zope.security import canAccess, canWrite from zope.security import canAccess, canWrite
from zope.security.proxy import removeSecurityProxy from zope.security.proxy import removeSecurityProxy
from loops.interfaces import IDocument, IMediaAsset from loops.interfaces import IDocument, IMediaAsset
from loops.browser.common import BaseView
from loops.browser.concept import ConceptRelationView, ConceptConfigureView
renderingFactories = { renderingFactories = {
'text/plain': 'zope.source.plaintext', 'text/plain': 'zope.source.plaintext',
@ -40,11 +43,69 @@ renderingFactories = {
} }
class DocumentView(object): class ResourceView(BaseView):
def __init__(self, context, request): def concepts(self):
self.context = context for r in self.context.getConceptRelations():
self.request = request yield ConceptRelationView(r, self.request)
class ResourceConfigureView(ResourceView, ConceptConfigureView):
def update(self):
request = self.request
action = request.get('action')
if action is None:
return True
if action == 'create':
self.createAndAssign()
return True
tokens = request.get('tokens', [])
for token in tokens:
parts = token.split(':')
token = parts[0]
if len(parts) > 1:
relToken = parts[1]
concept = self.loopsRoot.loopsTraverse(token)
if action == 'assign':
predicate = request.get('predicate') or None
if predicate:
predicate = removeSecurityProxy(
self.loopsRoot.loopsTraverse(predicate))
self.context.assignConcept(removeSecurityProxy(concept), predicate)
elif action == 'remove':
predicate = self.loopsRoot.loopsTraverse(relToken)
self.context.deassignConcept(concept, [predicate])
return True
def search(self):
request = self.request
if request.get('action') != 'search':
return []
searchTerm = request.get('searchTerm', None)
searchType = request.get('searchType', None)
result = []
if searchTerm or searchType != 'none':
criteria = {}
if searchTerm:
criteria['loops_title'] = searchTerm
if searchType:
if searchType.endswith('*'):
start = searchType[:-1]
end = start + '\x7f'
else:
start = end = searchType
criteria['loops_type'] = (start, end)
cat = zapi.getUtility(ICatalog)
result = cat.searchResults(**criteria)
else:
result = self.loopsRoot.getConceptManager().values()
if searchType == 'none':
result = [r for r in result if r.conceptType is None]
return self.viewIterator(result)
class DocumentView(ResourceView):
def render(self): def render(self):
""" Return the rendered content (data) of the context object. """ Return the rendered content (data) of the context object.

View file

@ -0,0 +1,49 @@
<tal:tag condition="view/update" />
<html metal:use-macro="context/@@standard_macros/view"
i18n:domain="loops">
<body>
<div metal:fill-slot="body">
<h1 tal:content="context/title">Concept Title</h1><br />
<div tal:define="items view/concepts;
action string:remove;
qualifier string:parents;
summary string:Currently assigned objects;
legend string:Parent Concepts;
showPredicate string:yes;
buttonText string:Remove Parents;"
style="padding-right:20px">
<metal:parents use-macro="views/relation_macros/listing" />
</div>
<div tal:define="items view/search;
action string:assign;
qualifier nothing;
summary string:Assignment candidates;
legend string:Search;
showPredicate nothing;
buttonText string:Assign;"
style="padding-right:20px">
<metal:assign use-macro="views/relation_macros/listing">
<metal:search fill-slot="topActions">
<metal:block use-macro="views/relation_macros/search" />
</metal:search>
<metal:special fill-slot="specialButtons">
Object(s) using Predicate
<select name="predicate">
<tal:types repeat="pred view/predicates">
<option value=".loops/concepts/hasType"
i18n:translate=""
tal:attributes="value pred/token"
tal:content="pred/title">Predicate</option>
</tal:types>
</select>
</metal:special>
</metal:assign>
</div>
</div>
</body>
</html>

View file

@ -173,7 +173,7 @@ class Concept(Contained, Persistent):
if predicate is None: if predicate is None:
predicate = self.getConceptManager().getDefaultPredicate() predicate = self.getConceptManager().getDefaultPredicate()
registry = zapi.getUtility(IRelationRegistry) registry = zapi.getUtility(IRelationRegistry)
registry.register(ResourceRelation(self, resource, predicate)) registry.register(ResourceRelation(self, resource))
# TODO (?): avoid duplicates # TODO (?): avoid duplicates
def deassignResource(self, resource, predicates=None): def deassignResource(self, resource, predicates=None):

View file

@ -205,10 +205,33 @@ class IResource(ILoopsObject, IPotentialTarget):
""" """
def getClients(relationships=None): def getClients(relationships=None):
""" Return a sequence of objects that are clients of the resource, """ Return a sequence of objects that the resource is the target of.
i.e. that have some relation with it.
""" """
def getConcepts(predicates=None):
""" Return a tuple of concepts related to self as parent concepts,
optionally restricted to the predicates given.
"""
def getConceptRelations(predicates=None, concepts=None):
""" Return a sequence of relations to concepts assigned to self
as parent concepts, optionally restricted to the predicates given
or to a certain concept.
"""
def assignConcept(concept, predicate):
""" Assign an existing concept to self using the predicate given.
The assigned concept will be a parent concept of self.
The predicate defaults to the concept manager's default predicate.
"""
def deassignConcept(concept, predicates=None):
""" Remove the concept relations to the concept given from self,
optionally restricting them to the predicates given.
"""
class IDocumentSchema(IResourceSchema): class IDocumentSchema(IResourceSchema):

View file

@ -27,6 +27,7 @@ from zope.app.container.btree import BTreeContainer
from zope.app.container.contained import Contained from zope.app.container.contained import Contained
from zope.app.file.image import Image as BaseMediaAsset from zope.app.file.image import Image as BaseMediaAsset
from zope.component import adapts from zope.component import adapts
from zope.i18nmessageid import MessageFactory
from zope.interface import implements from zope.interface import implements
from persistent import Persistent from persistent import Persistent
from cStringIO import StringIO from cStringIO import StringIO
@ -39,12 +40,18 @@ from interfaces import IMediaAsset, IMediaAssetSchema, IMediaAssetView
from interfaces import IResourceManager, IResourceManagerContained from interfaces import IResourceManager, IResourceManagerContained
from interfaces import ILoopsContained from interfaces import ILoopsContained
from interfaces import IIndexAttributes from interfaces import IIndexAttributes
from concept import ResourceRelation
from view import TargetRelation
_ = MessageFactory('loops')
class Resource(Contained, Persistent): class Resource(Contained, Persistent):
implements(IResource, IResourceManagerContained, IRelatable) implements(IResource, IResourceManagerContained, IRelatable)
_size = _width = _height = 0
_title = u'' _title = u''
def getTitle(self): return self._title def getTitle(self): return self._title
def setTitle(self, title): self._title = title def setTitle(self, title): self._title = title
@ -57,17 +64,34 @@ class Resource(Contained, Persistent):
def getContentType(self): return self._contentType def getContentType(self): return self._contentType
contentType = property(getContentType, setContentType) contentType = property(getContentType, setContentType)
def __init__(self, title=u''):
self.title = title
def getLoopsRoot(self): def getLoopsRoot(self):
return zapi.getParent(self).getLoopsRoot() return zapi.getParent(self).getLoopsRoot()
def getClients(self, relationships=None): def getClients(self, relationships=None):
if relationships is None:
relationships = [TargetRelation]
rels = getRelations(second=self, relationships=relationships) rels = getRelations(second=self, relationships=relationships)
return [r.first for r in rels] return [r.first for r in rels]
def __init__(self, title=u''): # concept relations
self.title = title
_size = _width = _height = 0 def getConceptRelations (self, predicates=None, concept=None):
predicates = predicates is None and ['*'] or predicates
relationships = [ResourceRelation(None, self, p) for p in predicates]
# TODO: sort...
return getRelations(first=concept, second=self, relationships=relationships)
def getConcepts(self, predicates=None):
return [r.first for r in self.getConceptRelations(predicates)]
def assignConcept(self, concept, predicate=None):
concept.assignResource(self, predicate)
def deassignConcept(self, concept, predicates=None):
concept.deassignResource(self, predicates)
class Document(Resource): class Document(Resource):
@ -138,3 +162,14 @@ class IndexAttributes(object):
context = self.context context = self.context
return ':'.join(('loops:resource', context.__class__.__name__)) return ':'.join(('loops:resource', context.__class__.__name__))
def getResourceTypes():
return (('loops.resource.Document', _(u'Document')),
('loops.resource.MediaAsset', _(u'Media Asset')),
)
def getResourceTypesForSearch():
return (('loops:resource:Document', _(u'Document')),
('loops:resource:MediaAsset', _(u'Media Asset')),
)