From bfbca480af3ba73fbf3623bbd761060dc17206c7 Mon Sep 17 00:00:00 2001 From: helmutm Date: Fri, 12 Feb 2010 17:08:59 +0000 Subject: [PATCH] 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 --- concept.py | 4 +- external/base.py | 79 ++++++++++++++++++++++++++++++++++------ external/browser.py | 5 +-- external/element.py | 14 +++++++ external/exportimport.pt | 8 ++-- resource.py | 7 ++-- 6 files changed, 94 insertions(+), 23 deletions(-) diff --git a/concept.py b/concept.py index c8c51b8..9c890e1 100644 --- a/concept.py +++ b/concept.py @@ -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 # it under the terms of the GNU General Public License as published by @@ -164,7 +164,7 @@ class Concept(Contained, Persistent): elif rel not in pi.relations: pi.relations.append(rel) return result - + def getLongTitle(self): return self.title diff --git a/external/base.py b/external/base.py index 5086e2e..058985b 100644 --- a/external/base.py +++ b/external/base.py @@ -39,10 +39,11 @@ from cybertools.typology.interfaces import IType from loops.common import adapted from loops.external.interfaces import ILoader, IExtractor, ISubExtractor 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.resource import Document, MediaAsset from loops.setup import SetupManager +from loops import util class Base(object): @@ -159,19 +160,44 @@ class Extractor(Base): self.count += 1 yield elem - def extractChanged(self, changedSince, parents=None, predicates=None, + def extractChanges(self, changedSince, parents=None, predicates=None, includeSubconcepts=False, includeResources=False,): - rm = self.context.getRecordManager() - if rm is not None: - changes = rm.get('changes') + changes = self.getChangeRecords() if not changes: - return [] + return + objects = [] + assignments = [] + deassignments = [] tracks = changes.query(timeFrom=changedSince) - # work in progress: TODO: - # select objects, - # check parents using predicates given, - # include children and resources if corresponding flags are set. - return [] + for tr in tracks: + obj = util.getObjectForUid(tr.taskId) + action = tr.data.get('action') + if action in ('add', 'modify'): + 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, includeSubconcepts=False, includeResources=False,): @@ -212,6 +238,37 @@ class Extractor(Base): # 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): if obj.conceptType is None: raise ValueError('Concept type is None for %s.' % getName(obj)) diff --git a/external/browser.py b/external/browser.py index 0dc99c8..1a6157e 100644 --- a/external/browser.py +++ b/external/browser.py @@ -81,8 +81,7 @@ class ExportImport(object): parents = [p for p in parents if p is not None] predicateIds = form.get('predicates') if predicateIds: - predicates = (predicateIds and [self.conceptManager[id] - for id in predicateIds] or None) + predicates = ([self.conceptManager[id] for id in predicateIds]) changed = form.get('changed') includeSubconcepts = form.get('include_subconcepts') includeResources = form.get('include_resources') @@ -90,7 +89,7 @@ class ExportImport(object): if changed: changed = self.parseDate(changed) if changed: - elements = extractor.extractChanged(changed, parents, predicates, + elements = extractor.extractChanges(changed, parents, predicates, includeSubconcepts, includeResources) elif parents: elements = extractor.extractForParents(parents, predicates, diff --git a/external/element.py b/external/element.py index da59dd3..07f3f51 100644 --- a/external/element.py +++ b/external/element.py @@ -190,6 +190,19 @@ class ResourceRelationElement(ChildElement): 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): elementType = 'node' @@ -230,6 +243,7 @@ elementTypes = dict( child=ChildElement, resource=ResourceElement, resourceRelation=ResourceRelationElement, + deassign=DeassignmentElement, node=NodeElement, layoutNode=LayoutNodeElement, I18NValue=I18NValue, diff --git a/external/exportimport.pt b/external/exportimport.pt index d0230ca..fe49e74 100644 --- a/external/exportimport.pt +++ b/external/exportimport.pt @@ -26,7 +26,7 @@
 
- + @@ -42,7 +42,7 @@

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