def __init__(self, *args, **kwargs): super(ReferenceService, self).__init__(*args, **kwargs) self.catalog = RelationCatalog() self.references = RelationsContainer()
class ReferenceService(SilvaService): """This service track existing references between content """ meta_type = 'Silva Reference Service' grok.name('service_reference') grok.implements(IReferenceService, ISilvaConfigurableService) silvaconf.default_service(setup=configure_service) silvaconf.icon('service.png') manage_options = ( {'label':'Broken references', 'action':'manage_brokenreferences'}, ) + SilvaService.manage_options def __init__(self, *args, **kwargs): super(ReferenceService, self).__init__(*args, **kwargs) self.catalog = RelationCatalog() self.references = RelationsContainer() def __create_reference(self, content_id, name=None, target_id=0, tags=None, factory=ReferenceValue): """Create and add a new reference """ if not IReferenceValue.implementedBy(factory): raise TypeError('Wrong factory %s for reference, ' 'it should implement IReferenceValue' % factory) if tags is None: tags = [] if name is not None: tags.append(name) reference = factory(content_id, target_id, tags=tags) reference_id = str(uuid.uuid4()) self.references[reference_id] = reference return reference def new_reference(self, content, name=None, factory=ReferenceValue): """Create a new reference. """ content_id = get_content_id(content) return self.__create_reference(content_id, name=name, factory=factory) def get_reference( self, content, name=None, add=False, factory=ReferenceValue): """Retrieve an existing reference. """ content_id = get_content_id(content) references = list(self.catalog.findRelations( {'source_id': content_id, 'tag': name})) if not len(references): if add is True: return self.__create_reference( content_id, name=name, factory=factory) return None return references[0] def get_references_to(self, content, name=None, depth=1): """Get all references to the given content. """ content_id = get_content_id(content) query = {'target_id': content_id} options = {} if name is not None: query['tag'] = name if depth: options['queryFactory'] = TransposingTransitive( 'source_id', 'target_id') options['maxDepth'] = depth return self.catalog.findRelations(query, **options) def get_references_from(self, content, name=None, depth=0): """Get all references from the given content. """ content_id = get_content_id(content) query = {'source_id': content_id} options = {} if name is not None: query['tag'] = name if depth: options['queryFactory'] = TransposingTransitive( 'souce_id', 'target_id') options['maxDepth'] = depth return self.catalog.findRelations(query, **options) def get_references_between(self, source, target, name=None): query = {'source_id': get_content_id(source), 'target_id': get_content_id(target)} if name is not None: query['tag'] = name return self.catalog.findRelations(query) def delete_reference(self, content, name=None): """Lookup and remove a reference. """ reference = self.get_reference(content, name=name, add=False) if reference is not None: del self.references[reference.__name__] def delete_references(self, content, name=None): """Lookup and remove a list of references. """ for reference in list(self.get_references_from(content, name=name)): del self.references[reference.__name__] def delete_reference_by_name(self, name): del self.references[name] def clone_references( self, content, clone, copy_source=None, copy_target=None): """Clone content reference to clone content unless source and target are both in container. """ content_id = get_content_id(content) clone_id = get_content_id(clone) references = self.catalog.findRelations({'source_id': content_id}) for reference in references: clone_target_id = reference.target_id if copy_source is not None and clone_target_id: target_path = reference.target.getPhysicalPath() copy_source_path = copy_source.getPhysicalPath() if (len(target_path) >= len(copy_source_path) and target_path[:len(copy_source_path)] == copy_source_path): # Reference target is in copy_source, so we need to # set target to the corresponding one in # copy_target. assert copy_target is not None relative_target_path = relative_path( copy_source_path, target_path) if relative_target_path != ['.']: clone_target = copy_target.unrestrictedTraverse( relative_target_path) else: clone_target = copy_target clone_target_id = get_content_id(clone_target) self.__create_reference( clone_id, target_id=clone_target_id, tags=list(reference.tags), factory=reference.__class__)