more on versioning: basically working
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1655 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
c35d7fab4e
commit
a66d7f81c7
12 changed files with 238 additions and 94 deletions
|
@ -51,6 +51,7 @@ from loops.resource import Resource
|
||||||
from loops.type import ITypeConcept
|
from loops.type import ITypeConcept
|
||||||
from loops import util
|
from loops import util
|
||||||
from loops.util import _
|
from loops.util import _
|
||||||
|
from loops.versioning.interfaces import IVersionable
|
||||||
|
|
||||||
|
|
||||||
class NameField(schema.ASCIILine):
|
class NameField(schema.ASCIILine):
|
||||||
|
@ -237,6 +238,22 @@ class BaseView(GenericView):
|
||||||
return util.KeywordVocabulary(general
|
return util.KeywordVocabulary(general
|
||||||
+ self.listTypesForSearch(('resource',), ('system', 'hidden'),))
|
+ self.listTypesForSearch(('resource',), ('system', 'hidden'),))
|
||||||
|
|
||||||
|
# versioning
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def versionInfo(self):
|
||||||
|
context = self.context
|
||||||
|
versionable = IVersionable(context, None)
|
||||||
|
if versionable is None:
|
||||||
|
return ''
|
||||||
|
versionId = versionable.versionId
|
||||||
|
current = (versionable.currentVersion == context) and 'current' or ''
|
||||||
|
released = (versionable.releasedVersion == context) and 'released' or ''
|
||||||
|
if not current and not released:
|
||||||
|
return versionId
|
||||||
|
addInfo = ', '.join(e for e in (current, released) if e)
|
||||||
|
return '%s (%s)' % (versionId, addInfo)
|
||||||
|
|
||||||
# controlling editing
|
# controlling editing
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
|
|
@ -51,6 +51,7 @@ from loops.resource import Resource
|
||||||
from loops.type import ITypeConcept
|
from loops.type import ITypeConcept
|
||||||
from loops import util
|
from loops import util
|
||||||
from loops.util import _
|
from loops.util import _
|
||||||
|
from loops.versioning.interfaces import IVersionable
|
||||||
|
|
||||||
|
|
||||||
# special widgets
|
# special widgets
|
||||||
|
@ -248,7 +249,14 @@ class EditObject(FormController):
|
||||||
selected = None
|
selected = None
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.updateFields(self.view.virtualTargetObject)
|
# create new version if necessary
|
||||||
|
target = self.view.virtualTargetObject
|
||||||
|
obj = self.checkCreateVersion(target)
|
||||||
|
if obj != target:
|
||||||
|
# make sure new version is used by the view
|
||||||
|
self.view.virtualTargetObject = obj
|
||||||
|
self.request.annotations['loops.view']['target'] = obj
|
||||||
|
self.updateFields(obj)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -314,6 +322,14 @@ class EditObject(FormController):
|
||||||
if not exists:
|
if not exists:
|
||||||
obj.assignConcept(concept, predicate)
|
obj.assignConcept(concept, predicate)
|
||||||
|
|
||||||
|
def checkCreateVersion(self, obj):
|
||||||
|
form = self.request.form
|
||||||
|
if form.get('version.create'):
|
||||||
|
versionable = IVersionable(obj)
|
||||||
|
level = int(form.get('version.level', 1))
|
||||||
|
return versionable.createVersion(level)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
|
||||||
class CreateObject(EditObject):
|
class CreateObject(EditObject):
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
<form method="post" enctype="multipart/form-data">
|
<form method="post" enctype="multipart/form-data">
|
||||||
<input type="hidden" name="form.action" value="edit"
|
<input type="hidden" name="form.action" value="edit"
|
||||||
tal:attributes="value view/form_action" />
|
tal:attributes="value view/form_action" />
|
||||||
|
<input type="hidden" name="version"
|
||||||
|
tal:attributes="value request/version | nothing" />
|
||||||
<table cellpadding="3" class="form">
|
<table cellpadding="3" class="form">
|
||||||
<tbody><tr><th colspan="5"><br />
|
<tbody><tr><th colspan="5"><br />
|
||||||
<span tal:replace="view/title"
|
<span tal:replace="view/title"
|
||||||
|
@ -24,6 +26,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr metal:use-macro="view/template/macros/assignments" />
|
<tr metal:use-macro="view/template/macros/assignments" />
|
||||||
<tr metal:use-macro="view/template/macros/search_concepts" />
|
<tr metal:use-macro="view/template/macros/search_concepts" />
|
||||||
|
<tr metal:use-macro="view/template/macros/versioning" />
|
||||||
<tr metal:use-macro="view/template/macros/buttons" />
|
<tr metal:use-macro="view/template/macros/buttons" />
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -165,6 +168,33 @@
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
<metal:versioning define-macro="versioning"
|
||||||
|
tal:define="versionInfo view/versionInfo"
|
||||||
|
tal:condition="versionInfo">
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" class="headline">Versioning</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
Version:
|
||||||
|
<span tal:content="versionInfo">1.1 (current, released)</span>
|
||||||
|
</td>
|
||||||
|
<td title="Select if you want to create a new version">
|
||||||
|
<input type="checkbox"
|
||||||
|
name="version.create" id="version.create"
|
||||||
|
value="create" />
|
||||||
|
<label for="version.create">New version:</label>
|
||||||
|
</td>
|
||||||
|
<td colspan="2">
|
||||||
|
<select name="version.level">
|
||||||
|
<option value="1">minor</option>
|
||||||
|
<option value="0">major</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</metal:versioning>
|
||||||
|
|
||||||
|
|
||||||
<tr metal:define-macro="buttons">
|
<tr metal:define-macro="buttons">
|
||||||
<td colspan="5"
|
<td colspan="5"
|
||||||
tal:define="dlgName view/dialog_name">
|
tal:define="dlgName view/dialog_name">
|
||||||
|
|
|
@ -226,7 +226,9 @@
|
||||||
<div tal:condition="view/hasEditableTarget">
|
<div tal:condition="view/hasEditableTarget">
|
||||||
<a href="#"
|
<a href="#"
|
||||||
onclick="objectDialog('edit', 'edit_object.html'); return false;"
|
onclick="objectDialog('edit', 'edit_object.html'); return false;"
|
||||||
tal:attributes="onclick string:objectDialog('edit', '$url/edit_object.html');; return false;;">
|
tal:define="version request/version|nothing;
|
||||||
|
versionPar python: version and '?version=$version' or ''"
|
||||||
|
tal:attributes="onclick string:objectDialog('edit', '$url/edit_object.html$versionPar');; return false;;">
|
||||||
Edit Resource...
|
Edit Resource...
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
40
resource.py
40
resource.py
|
@ -47,16 +47,17 @@ from cybertools.storage.interfaces import IExternalStorage
|
||||||
from cybertools.text.interfaces import ITextTransform
|
from cybertools.text.interfaces import ITextTransform
|
||||||
from cybertools.typology.interfaces import IType, ITypeManager
|
from cybertools.typology.interfaces import IType, ITypeManager
|
||||||
|
|
||||||
from interfaces import IBaseResource, IResource
|
from loops.interfaces import IBaseResource, IResource
|
||||||
from interfaces import IFile, IExternalFile, INote
|
from loops.interfaces import IFile, IExternalFile, INote
|
||||||
from interfaces import IDocument, ITextDocument, IDocumentSchema, IDocumentView
|
from loops.interfaces import IDocument, ITextDocument, IDocumentSchema, IDocumentView
|
||||||
from interfaces import IMediaAsset, IMediaAssetView
|
from loops.interfaces import IMediaAsset, IMediaAssetView
|
||||||
from interfaces import IResourceManager, IResourceManagerContained
|
from loops.interfaces import IResourceManager, IResourceManagerContained
|
||||||
from interfaces import ILoopsContained
|
from loops.interfaces import ILoopsContained
|
||||||
from interfaces import IIndexAttributes
|
from loops.interfaces import IIndexAttributes
|
||||||
from concept import ResourceRelation
|
from loops.concept import ResourceRelation
|
||||||
from common import ResourceAdapterBase
|
from loops.common import ResourceAdapterBase
|
||||||
from view import TargetRelation
|
from loops.versioning.util import getMaster
|
||||||
|
from loops.view import TargetRelation
|
||||||
|
|
||||||
_ = MessageFactory('loops')
|
_ = MessageFactory('loops')
|
||||||
|
|
||||||
|
@ -147,26 +148,31 @@ class Resource(Image, Contained):
|
||||||
def getClients(self, relationships=None):
|
def getClients(self, relationships=None):
|
||||||
if relationships is None:
|
if relationships is None:
|
||||||
relationships = [TargetRelation]
|
relationships = [TargetRelation]
|
||||||
# Versioning: obj = IVersionable(self).master
|
obj = getMaster(self) # use the master version for relations
|
||||||
rels = getRelations(second=self, relationships=relationships)
|
rels = getRelations(second=obj, relationships=relationships)
|
||||||
return [r.first for r in rels]
|
return [r.first for r in rels]
|
||||||
|
|
||||||
# concept relations
|
# concept relations
|
||||||
|
# note: we always use the master version for relations, see getMaster()
|
||||||
|
|
||||||
def getConceptRelations (self, predicates=None, concept=None):
|
def getConceptRelations (self, predicates=None, concept=None):
|
||||||
predicates = predicates is None and ['*'] or predicates
|
predicates = predicates is None and ['*'] or predicates
|
||||||
relationships = [ResourceRelation(None, self, p) for p in predicates]
|
obj = getMaster(self)
|
||||||
|
relationships = [ResourceRelation(None, obj, p) for p in predicates]
|
||||||
# TODO: sort...
|
# TODO: sort...
|
||||||
return getRelations(first=concept, second=self, relationships=relationships)
|
return getRelations(first=concept, second=obj, relationships=relationships)
|
||||||
|
|
||||||
def getConcepts(self, predicates=None):
|
def getConcepts(self, predicates=None):
|
||||||
return [r.first for r in self.getConceptRelations(predicates)]
|
obj = getMaster(self)
|
||||||
|
return [r.first for r in obj.getConceptRelations(predicates)]
|
||||||
|
|
||||||
def assignConcept(self, concept, predicate=None):
|
def assignConcept(self, concept, predicate=None):
|
||||||
concept.assignResource(self, predicate)
|
obj = getMaster(self)
|
||||||
|
concept.assignResource(obj, predicate)
|
||||||
|
|
||||||
def deassignConcept(self, concept, predicates=None):
|
def deassignConcept(self, concept, predicates=None):
|
||||||
concept.deassignResource(self, predicates)
|
obj = getMaster(self)
|
||||||
|
concept.deassignResource(obj, predicates)
|
||||||
|
|
||||||
# ISized interface
|
# ISized interface
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ Setting up a loops Site and Utilities
|
||||||
Let's do some basic set up
|
Let's do some basic set up
|
||||||
|
|
||||||
>>> from zope import component, interface
|
>>> from zope import component, interface
|
||||||
|
>>> from zope.traversing.api import getName
|
||||||
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
||||||
>>> site = placefulSetUp(True)
|
>>> site = placefulSetUp(True)
|
||||||
|
|
||||||
|
@ -42,6 +43,8 @@ We can access versioning information for an object by using an IVersionable
|
||||||
adapter on the object.
|
adapter on the object.
|
||||||
|
|
||||||
>>> d001 = resources['d001.txt']
|
>>> d001 = resources['d001.txt']
|
||||||
|
>>> d001.title
|
||||||
|
u'Doc 001'
|
||||||
>>> vD001 = IVersionable(d001)
|
>>> vD001 = IVersionable(d001)
|
||||||
|
|
||||||
If there aren't any versions associated with the object we get the default
|
If there aren't any versions associated with the object we get the default
|
||||||
|
@ -55,14 +58,70 @@ values:
|
||||||
{}
|
{}
|
||||||
>>> vD001.currentVersion is d001
|
>>> vD001.currentVersion is d001
|
||||||
True
|
True
|
||||||
>>> vD001.releasedVersion is d001
|
>>> vD001.releasedVersion is None
|
||||||
True
|
True
|
||||||
|
|
||||||
Now we can create a new version for our document:
|
Now we can create a new version for our document:
|
||||||
|
|
||||||
>>> d001v1_1 = vD001.createVersion()
|
>>> d001v1_2 = vD001.createVersion()
|
||||||
>>> sorted(resources)
|
>>> getName(d001v1_2)
|
||||||
|
u'd001_1.2.txt'
|
||||||
|
>>> d001v1_2.title
|
||||||
|
u'Doc 001'
|
||||||
|
|
||||||
>>> vD001v1_1 = IVersionable(d001v1_1)
|
>>> vD001v1_2 = IVersionable(d001v1_2)
|
||||||
>>> vD001v1_1.versionId
|
>>> vD001v1_2.versionId
|
||||||
'1.2'
|
'1.2'
|
||||||
|
|
||||||
|
>>> vD001.currentVersion is d001v1_2
|
||||||
|
True
|
||||||
|
>>> vD001.master is d001
|
||||||
|
True
|
||||||
|
>>> vD001v1_2.master is d001
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> sorted(vD001.versions)
|
||||||
|
['1.1', '1.2']
|
||||||
|
|
||||||
|
When we use a higer level (i.e. a lower number for level) to denote
|
||||||
|
a major version change, the lower levels are reset to 1:
|
||||||
|
|
||||||
|
>>> d001v2_1 = vD001.createVersion(0)
|
||||||
|
>>> getName(d001v2_1)
|
||||||
|
u'd001_2.1.txt'
|
||||||
|
|
||||||
|
|
||||||
|
Providing the Correct Version
|
||||||
|
=============================
|
||||||
|
|
||||||
|
When accessing resources as targets for view nodes, the node's traversal adapter
|
||||||
|
(see loops.view.NodeTraverser) uses the versioning framework to retrieve
|
||||||
|
the correct version of a resource by calling the getVersion() function.
|
||||||
|
|
||||||
|
>>> from loops.versioning.util import getVersion
|
||||||
|
>>> from zope.publisher.browser import TestRequest
|
||||||
|
|
||||||
|
The default version is always the released or - if this is not available -
|
||||||
|
the current version (i.e. the version created most recently):
|
||||||
|
|
||||||
|
>>> IVersionable(getVersion(d001, TestRequest())).versionId
|
||||||
|
'2.1'
|
||||||
|
|
||||||
|
>>> IVersionable(getVersion(d001v1_2, TestRequest())).versionId
|
||||||
|
'2.1'
|
||||||
|
|
||||||
|
>>> d002 = resources['d002.txt']
|
||||||
|
>>> IVersionable(getVersion(d002, TestRequest())).versionId
|
||||||
|
'1.1'
|
||||||
|
|
||||||
|
When using the expression "version=this" as a URL parameter the object
|
||||||
|
addressed will be returned without looking for a special version:
|
||||||
|
|
||||||
|
>>> IVersionable(getVersion(d001, TestRequest(form=dict(version='this')))).versionId
|
||||||
|
'1.1'
|
||||||
|
|
||||||
|
In addition it is possible to explicitly retrieve a certain version:
|
||||||
|
|
||||||
|
>>> IVersionable(getVersion(d001v1_2, TestRequest(form=dict(version='1.1')))).versionId
|
||||||
|
'1.1'
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,3 @@ class IVersionable(Interface):
|
||||||
The level provides the position in the variantIds tuple.
|
The level provides the position in the variantIds tuple.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class IVersionInfo(Interface):
|
|
||||||
""" Versioning metadata, e.g. criteria for version selection.
|
|
||||||
"""
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import unittest, doctest
|
import unittest, doctest
|
||||||
from zope.testing.doctestunit import DocFileSuite
|
from zope.testing.doctestunit import DocFileSuite
|
||||||
from zope.interface.verify import verifyClass
|
from zope.interface.verify import verifyClass
|
||||||
from loops.versioning import versioninfo
|
from loops.versioning import versionable
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
"Basic tests for the expert sub-package."
|
"Basic tests for the expert sub-package."
|
||||||
|
|
57
versioning/util.py
Normal file
57
versioning/util.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2007 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Utilities for managing version informations.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from loops.versioning.interfaces import IVersionable
|
||||||
|
|
||||||
|
|
||||||
|
def getVersion(obj, request):
|
||||||
|
""" Check if another version should be used for the object
|
||||||
|
provided and return it.
|
||||||
|
"""
|
||||||
|
versionRequest = request.form.get('version')
|
||||||
|
if versionRequest == 'this':
|
||||||
|
# we really want this object, not another version
|
||||||
|
return obj
|
||||||
|
versionable = IVersionable(obj, None)
|
||||||
|
if versionable is None:
|
||||||
|
return obj
|
||||||
|
if not versionRequest:
|
||||||
|
# find and return a standard version
|
||||||
|
v = versionable.releasedVersion
|
||||||
|
if v is None:
|
||||||
|
v = versionable.currentVersion
|
||||||
|
return v
|
||||||
|
# we might have a versionId in the request
|
||||||
|
v = versionable.versions.get(versionRequest)
|
||||||
|
if v is not None:
|
||||||
|
return v
|
||||||
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
def getMaster(obj):
|
||||||
|
versionable = IVersionable(obj, None)
|
||||||
|
if versionable is None:
|
||||||
|
return obj
|
||||||
|
return versionable.master
|
||||||
|
|
|
@ -24,8 +24,9 @@ $Id$
|
||||||
|
|
||||||
from BTrees.OOBTree import OOBTree
|
from BTrees.OOBTree import OOBTree
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
from zope.interface import implements
|
from zope.interface import implements, Attribute
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope.schema.interfaces import IField
|
||||||
from zope.traversing.api import getName, getParent
|
from zope.traversing.api import getName, getParent
|
||||||
|
|
||||||
from cybertools.text.mimetypes import extensions
|
from cybertools.text.mimetypes import extensions
|
||||||
|
@ -55,16 +56,19 @@ class VersionableResource(object):
|
||||||
return default
|
return default
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def initVersioningAttribute(self, attr, value):
|
|
||||||
attrName = attrPattern % attr
|
|
||||||
value = getattr(self.context, attrName, _not_found)
|
|
||||||
if value is _not_found:
|
|
||||||
setattr(self.context, attrName, value)
|
|
||||||
|
|
||||||
def setVersioningAttribute(self, attr, value):
|
def setVersioningAttribute(self, attr, value):
|
||||||
attrName = attrPattern % attr
|
attrName = attrPattern % attr
|
||||||
setattr(self.context, attrName, value)
|
setattr(self.context, attrName, value)
|
||||||
|
|
||||||
|
def initVersions(self):
|
||||||
|
attrName = attrPattern % 'versions'
|
||||||
|
value = getattr(self.context, attrName, _not_found)
|
||||||
|
if value is _not_found:
|
||||||
|
versions = OOBTree()
|
||||||
|
versions['1.1'] = self.context
|
||||||
|
setattr(self.context, attrName, versions)
|
||||||
|
#self.versions['1.1'] = self.context
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def versionNumbers(self):
|
def versionNumbers(self):
|
||||||
return self.getVersioningAttribute('versionNumbers', (1, 1))
|
return self.getVersioningAttribute('versionNumbers', (1, 1))
|
||||||
|
@ -98,7 +102,7 @@ class VersionableResource(object):
|
||||||
@property
|
@property
|
||||||
def releasedVersion(self):
|
def releasedVersion(self):
|
||||||
m = self.versionableMaster
|
m = self.versionableMaster
|
||||||
return self.versionableMaster.getVersioningAttribute('releasedVersion', self.master)
|
return self.versionableMaster.getVersioningAttribute('releasedVersion', None)
|
||||||
|
|
||||||
def createVersion(self, level=1):
|
def createVersion(self, level=1):
|
||||||
context = self.context
|
context = self.context
|
||||||
|
@ -108,6 +112,9 @@ class VersionableResource(object):
|
||||||
while len(vn) <= level:
|
while len(vn) <= level:
|
||||||
vn.append(1)
|
vn.append(1)
|
||||||
vn[level] += 1
|
vn[level] += 1
|
||||||
|
for l in range(level+1, len(vn)):
|
||||||
|
# reset lower levels
|
||||||
|
vn[l] = 1
|
||||||
# create new object
|
# create new object
|
||||||
cls = context.__class__
|
cls = context.__class__
|
||||||
obj = cls()
|
obj = cls()
|
||||||
|
@ -123,18 +130,17 @@ class VersionableResource(object):
|
||||||
versionId)
|
versionId)
|
||||||
getParent(context)[name] = obj
|
getParent(context)[name] = obj
|
||||||
# set resource attributes
|
# set resource attributes
|
||||||
obj.resourceType = context.resourceType
|
|
||||||
ti = IType(context).typeInterface
|
ti = IType(context).typeInterface
|
||||||
if ti is not None:
|
attrs = set((ti and list(ti) or [])
|
||||||
adaptedContext = ti(context)
|
+ ['title', 'description', 'data', 'contentType'])
|
||||||
adaptedObj = ti(obj)
|
adaptedContext = ti and ti(context) or context
|
||||||
for attr in ti:
|
adaptedObj = ti and ti(obj) or obj
|
||||||
if attr not in ('resourceType',):
|
for attr in attrs:
|
||||||
setattr(adaptedObj, attr, getattr(adaptedContext, attr))
|
setattr(adaptedObj, attr, getattr(adaptedContext, attr))
|
||||||
# set attributes of the master version
|
# set attributes of the master version
|
||||||
versionableMaster.initVersioningAttribute('versions', OOBTree())
|
|
||||||
self.versions[versionId] = obj
|
|
||||||
versionableMaster.setVersioningAttribute('currentVersion', obj)
|
versionableMaster.setVersioningAttribute('currentVersion', obj)
|
||||||
|
versionableMaster.initVersions()
|
||||||
|
self.versions[versionId] = obj
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def generateName(self, name, ext, versionId):
|
def generateName(self, name, ext, versionId):
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
#
|
|
||||||
# Copyright (c) 2007 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
|
|
||||||
#
|
|
||||||
|
|
||||||
"""
|
|
||||||
Utilities for managing version informations.
|
|
||||||
|
|
||||||
$Id$
|
|
||||||
"""
|
|
||||||
|
|
||||||
from zope.interface import implements
|
|
||||||
|
|
||||||
from loops.versioning.interfaces import IVersionInfo
|
|
||||||
|
|
||||||
|
|
||||||
class VersionInfo(object):
|
|
||||||
""" Collects and provides informations related to object versions.
|
|
||||||
"""
|
|
||||||
|
|
||||||
implements(IVersionInfo)
|
|
||||||
|
|
||||||
|
|
||||||
def getVersionInfo(obj, request):
|
|
||||||
""" Check if a special version should be used for the object
|
|
||||||
provided.
|
|
||||||
|
|
||||||
In addition return meta information about the object versions
|
|
||||||
so that this will not have to be retrieved later.
|
|
||||||
"""
|
|
||||||
return obj, VersionInfo()
|
|
7
view.py
7
view.py
|
@ -45,7 +45,7 @@ from loops.interfaces import IViewManager, INodeContained
|
||||||
from loops.interfaces import ILoopsContained
|
from loops.interfaces import ILoopsContained
|
||||||
from loops.interfaces import ITargetRelation
|
from loops.interfaces import ITargetRelation
|
||||||
from loops.interfaces import IConcept
|
from loops.interfaces import IConcept
|
||||||
from loops.versioning.versioninfo import getVersionInfo
|
from loops.versioning.util import getVersion
|
||||||
|
|
||||||
|
|
||||||
class View(object):
|
class View(object):
|
||||||
|
@ -203,8 +203,6 @@ class NodeTraverser(ItemTraverser):
|
||||||
else:
|
else:
|
||||||
target = self.context.target
|
target = self.context.target
|
||||||
if target is not None:
|
if target is not None:
|
||||||
# provide versioning info and switch to correct version if appropriate
|
|
||||||
target, versionInfo = getVersionInfo(target, request)
|
|
||||||
# remember self.context in request
|
# remember self.context in request
|
||||||
viewAnnotations = request.annotations.setdefault('loops.view', {})
|
viewAnnotations = request.annotations.setdefault('loops.view', {})
|
||||||
viewAnnotations['node'] = self.context
|
viewAnnotations['node'] = self.context
|
||||||
|
@ -212,9 +210,10 @@ class NodeTraverser(ItemTraverser):
|
||||||
# we have to use the target object directly
|
# we have to use the target object directly
|
||||||
return target
|
return target
|
||||||
else:
|
else:
|
||||||
|
# switch to correct version if appropriate
|
||||||
|
target = getVersion(target, request)
|
||||||
# we'll use the target object in the node's context
|
# we'll use the target object in the node's context
|
||||||
viewAnnotations['target'] = target
|
viewAnnotations['target'] = target
|
||||||
viewAnnotations['versionInfo'] = versionInfo
|
|
||||||
return self.context
|
return self.context
|
||||||
return super(NodeTraverser, self).publishTraverse(request, name)
|
return super(NodeTraverser, self).publishTraverse(request, name)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue