work in progress: synchronization, i.e. export and import of changes

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3727 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2010-02-12 17:08:59 +00:00
parent d12dac7e37
commit bfbca480af
6 changed files with 94 additions and 23 deletions

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de # Copyright (c) 2010 Helmut Merz helmutm@cy55.de
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by

79
external/base.py vendored
View file

@ -39,10 +39,11 @@ from cybertools.typology.interfaces import IType
from loops.common import adapted from loops.common import adapted
from loops.external.interfaces import ILoader, IExtractor, ISubExtractor from loops.external.interfaces import ILoader, IExtractor, ISubExtractor
from loops.external.element import elementTypes from loops.external.element import elementTypes
from loops.interfaces import IConceptSchema, IResourceSchema from loops.interfaces import IConceptSchema, IResourceSchema, IResource
from loops.layout.base import LayoutNode from loops.layout.base import LayoutNode
from loops.resource import Document, MediaAsset from loops.resource import Document, MediaAsset
from loops.setup import SetupManager from loops.setup import SetupManager
from loops import util
class Base(object): class Base(object):
@ -159,19 +160,44 @@ class Extractor(Base):
self.count += 1 self.count += 1
yield elem yield elem
def extractChanged(self, changedSince, parents=None, predicates=None, def extractChanges(self, changedSince, parents=None, predicates=None,
includeSubconcepts=False, includeResources=False,): includeSubconcepts=False, includeResources=False,):
rm = self.context.getRecordManager() changes = self.getChangeRecords()
if rm is not None:
changes = rm.get('changes')
if not changes: if not changes:
return [] return
objects = []
assignments = []
deassignments = []
tracks = changes.query(timeFrom=changedSince) tracks = changes.query(timeFrom=changedSince)
# work in progress: TODO: for tr in tracks:
# select objects, obj = util.getObjectForUid(tr.taskId)
# check parents using predicates given, action = tr.data.get('action')
# include children and resources if corresponding flags are set. if action in ('add', 'modify'):
return [] if not self.checkParents(obj, parents, predicates):
continue
if obj not in objects:
objects.append(obj)
name = getName(obj)
yield self.getConceptOrResourceElement(name, obj)
elif action in ('assign', 'deassign'):
child = util.getObjectForUid(tr.data['second'])
pred = util.getObjectForUid(tr.data['predicate'])
if child is None or pred is None:
# may have been deleted already - can be ignored
continue
if (not self.checkParents(obj, parents, predicates) and
not self.checkParents(child, parents, predicates)):
continue
if action == 'assign':
element = self.getAssignmentElement(obj, child, pred)
else:
element = self.getDeassignmentElement(obj, child, pred)
if element is not None:
yield element
# TODO: include new parent and child relations
# TODO: include statements for removal of relations if necessary
# (or remove relations not in import file upon import)
# TODO: include children and resources if corresponding flags are set.
def extractForParents(self, parents, predicates=None, def extractForParents(self, parents, predicates=None,
includeSubconcepts=False, includeResources=False,): includeSubconcepts=False, includeResources=False,):
@ -212,6 +238,37 @@ class Extractor(Base):
# helper methods # helper methods
def getChangeRecords(self):
rm = self.context.getRecordManager()
if rm is not None:
return rm.get('changes')
def checkParents(self, obj, parents, predicates):
if not parents:
return True
objParents = obj.getParents(predicates)
for p in parents:
if p in objParents:
return True
return False
def getConceptOrResourceElement(self, name, obj):
if IResource.providedBy(obj):
return self.getResourceElement(name, obj)
return self.getConceptElement(name, obj)
def getAssignmentElement(self, obj, child, predicate):
if IResource.providedBy(obj):
for r in obj.getResourceRelations([predicate], child):
return self.getResourceRelationElement(r)
else:
for r in obj.getChildRelations([predicate], child):
return self.getChildElement(r)
def getDeassignmentElement(self, obj, child, predicate):
args = getName(obj), getName(child), getName(predicate)
return elementTypes['deassign'](*args)
def getConceptElement(self, name, obj): def getConceptElement(self, name, obj):
if obj.conceptType is None: if obj.conceptType is None:
raise ValueError('Concept type is None for %s.' % getName(obj)) raise ValueError('Concept type is None for %s.' % getName(obj))

5
external/browser.py vendored
View file

@ -81,8 +81,7 @@ class ExportImport(object):
parents = [p for p in parents if p is not None] parents = [p for p in parents if p is not None]
predicateIds = form.get('predicates') predicateIds = form.get('predicates')
if predicateIds: if predicateIds:
predicates = (predicateIds and [self.conceptManager[id] predicates = ([self.conceptManager[id] for id in predicateIds])
for id in predicateIds] or None)
changed = form.get('changed') changed = form.get('changed')
includeSubconcepts = form.get('include_subconcepts') includeSubconcepts = form.get('include_subconcepts')
includeResources = form.get('include_resources') includeResources = form.get('include_resources')
@ -90,7 +89,7 @@ class ExportImport(object):
if changed: if changed:
changed = self.parseDate(changed) changed = self.parseDate(changed)
if changed: if changed:
elements = extractor.extractChanged(changed, parents, predicates, elements = extractor.extractChanges(changed, parents, predicates,
includeSubconcepts, includeResources) includeSubconcepts, includeResources)
elif parents: elif parents:
elements = extractor.extractForParents(parents, predicates, elements = extractor.extractForParents(parents, predicates,

14
external/element.py vendored
View file

@ -190,6 +190,19 @@ class ResourceRelationElement(ChildElement):
relevance = self.get('relevance') or 1.0) relevance = self.get('relevance') or 1.0)
class DeassignmentElement(Element):
elementType = 'deassign'
posArgs = ('first', 'second', 'predicate')
def __init__(self, *args):
for idx, arg in enumerate(args):
self[self.posArgs[idx]] = arg
def execute(self, loader):
loader.deassignResource(self['first'], self['second'], self['predicate'])
class NodeElement(Element): class NodeElement(Element):
elementType = 'node' elementType = 'node'
@ -230,6 +243,7 @@ elementTypes = dict(
child=ChildElement, child=ChildElement,
resource=ResourceElement, resource=ResourceElement,
resourceRelation=ResourceRelationElement, resourceRelation=ResourceRelationElement,
deassign=DeassignmentElement,
node=NodeElement, node=NodeElement,
layoutNode=LayoutNodeElement, layoutNode=LayoutNodeElement,
I18NValue=I18NValue, I18NValue=I18NValue,

View file

@ -26,7 +26,7 @@
<div>&nbsp;</div> <div>&nbsp;</div>
<div class="row"> <div class="row">
<table> <table>
<tr tal:condition="nothing"> <tr tal:condition="string:nothing">
<td> <td>
<label for="changed">Export only objects changed since:<br /> <label for="changed">Export only objects changed since:<br />
(YYYY-MM-DD[ HH:MM[:SS]])</label></td> (YYYY-MM-DD[ HH:MM[:SS]])</label></td>
@ -42,7 +42,7 @@
</td> </td>
<td> <td>
<label for="predicates">Predicates</label><br /> <label for="predicates">Predicates</label><br />
<select multiple name="predicates" id="predicates" <select multiple name="predicates:list" id="predicates"
size="9"> size="9">
<option tal:repeat="pred view/predicates" <option tal:repeat="pred view/predicates"
tal:attributes="value pred/name" tal:attributes="value pred/name"
@ -52,11 +52,11 @@
<br /> <br />
<input type="checkbox" name="include_subconcepts" <input type="checkbox" name="include_subconcepts"
id="include_subconcepts" /> id="include_subconcepts" />
<label for="include_subconcepts">Include Subconcepts</label> <label for="include_subconcepts">Include Assigned Subconcepts</label>
<br /> <br />
<input type="checkbox" name="include_resources" <input type="checkbox" name="include_resources"
id="include_resources" /> id="include_resources" />
<label for="include_resources">Include Resources</label> <label for="include_resources">Include Assigned Resources</label>
</td> </td>
</tr> </tr>
</table> </table>

View file

@ -201,14 +201,15 @@ class Resource(Image, Contained):
if canListObject(r.first, noSecurityCheck)) if canListObject(r.first, noSecurityCheck))
return sorted(rels, key=sort) return sorted(rels, key=sort)
# simplify common access for concepts and resources:
getParentRelations = getConceptRelations
def getConcepts(self, predicates=None, noSecurityCheck=False): def getConcepts(self, predicates=None, noSecurityCheck=False):
obj = getMaster(self) obj = getMaster(self)
return [r.first for r in obj.getConceptRelations(predicates, return [r.first for r in obj.getConceptRelations(predicates,
noSecurityCheck=noSecurityCheck)] noSecurityCheck=noSecurityCheck)]
# simplify common access for concepts and resources:
getParentRelations = getConceptRelations
getParents = getConcepts
def assignConcept(self, concept, predicate=None, order=0, relevance=1.0): def assignConcept(self, concept, predicate=None, order=0, relevance=1.0):
obj = getMaster(self) obj = getMaster(self)
concept.assignResource(obj, predicate, order, relevance) concept.assignResource(obj, predicate, order, relevance)