def get_lookup_content(content): if IVersion.providedBy(content): content = content.get_silva_object() if (ISilvaObject.providedBy(content) and not IContainer.providedBy(content)): return content.get_container() return content
def get_selected_contents(self, key='content', recursive=False): for content in self.get_contents(self.request.form.get(key)): if recursive and IContainer.providedBy(content): for content in walk_silva_tree(content): yield content else: yield content
def walk_silva_tree_ex(content, requires=ISilvaObject, version=False): """A controllable generator to lazily get all the Silva object from a content / container. Send it True to recursively go down, or False to skip the recursion. """ count = 0 want_next = True if requires.providedBy(content): want_next = yield content if want_next: if IContainer.providedBy(content): for child in content.objectValues(): walker_next = None walker = walk_silva_tree_ex(child, requires, version) while True: count += 1 try: walker_next = yield walker.send(walker_next) except StopIteration: break if count > THRESHOLD: # Review ZODB cache content._p_jar.cacheGC() count = 0 if version and IVersionedContent.providedBy(content): yield content.get_previewable()
def _perform_search(self, query, root, ignore_case, search_targets): """ walk through (part of) the site in search of query matches returns a list of dicts with keys 'path', 'occurrences', 'title' and 'state' """ ret = [] buffer = [root] processed = 0 occurrences = 0 while buffer: current = buffer.pop(0) # XXX or do we want depth first? if IContainer.providedBy(current): buffer += current.objectValues() elif IContent.providedBy(current): content_objects = self._get_content_objects(current) processed += len(content_objects) for state, url, obj in content_objects: content = self._get_silvaxml_content(obj) if content is None: continue num = self._count_or_replace( content, query, None, ignore_case, search_targets) occurrences += num if num > 0: ret.append({ 'url': url, 'path': '/'.join(obj.getPhysicalPath()), 'title': obj.get_title(), 'occurrences': num, 'state': state, }) return processed, occurrences, ret
def run(self, root, options): path = options.target if not path.startswith('/'): path = '/' + path container_path, content_id = path.rsplit('/', 1) try: import_root = root.restrictedTraverse(container_path) except KeyError: logger.error('Invalid path') exit(1) if not IContainer.providedBy(import_root): logger.error('Import root is not a container') exit(2) if options.broken: ExportImport._importDuringCommit = import_during_commit sys.meta_path.append(BrokenModuleFinder()) with open(options.file, 'rb') as f: logger.info('Importing...') content = import_root._p_jar.importFile(f) logger.info('Inserting content at %s...', "/".join(import_root.getPhysicalPath()) + path) import_root._setObject(content_id, content) content.id = content_id
def getValue(self): reference = self.service.get_reference(self.query, name=self.name) if reference is not None: target = reference.target if IContainer.providedBy(target): return target return None
def upgrade(self, content): identifier = content.getId() container = content.aq_parent if not IContainer.providedBy(container): logger.error(u'Invalid file: %s', content_path(content)) # Self-autodestruct file. container._delObject(identifier) raise StopIteration ghost = self.upgrade_to_ghost(content) if ghost is not None: return ghost new_file = BlobFile(identifier) tmp_identifier = identifier + 'conv_storage' container._setObject(tmp_identifier, new_file) new_file = container._getOb(tmp_identifier) self.replace_references(content, new_file) self.replace(content, new_file) new_file.set_file( content.get_file_fd(), content_type=content.get_content_type(), content_encoding=content.get_content_encoding()) container._delObject(identifier) container.manage_renameObject(tmp_identifier, identifier) logger.info(u"File rebuilt: %s.", content_path(new_file)) return new_file
def update(self): if self.toc_container is None: self.toc_container = self.context.get_container() assert IContainer.providedBy(self.toc_container) if self.toc_content_types is None: addables = IAddableContents(self.toc_container) self.toc_content_types = addables.get_container_addables(IPublishable)
def __call__(self, content): if IContainer.providedBy(content): default = content.get_default() if default is None: return True if self.get(default) is None: return True return False
def update(self): if self.toc_container is None: self.toc_container = self.context.get_container() assert IContainer.providedBy(self.toc_container) if self.toc_content_types is None: addables = IAddableContents(self.toc_container) self.toc_content_types = addables.get_container_addables( IPublishable)
def walker(context): if requires.providedBy(context): # Version are indexed by the versioned content itself yield context if IContainer.providedBy(context): for child in context.objectValues(): for context in walker(child): yield context elif version and IVersionedContent.providedBy(context): yield context.get_previewable()
def _get_public_tree_helper(self, l, indent, depth, include_publications, filters): for item in self.context.get_ordered_publishables(): if not filters(item): continue l.append((indent, item)) if (IContainer.providedBy(item) and (item.is_transparent() or include_publications)): if depth == -1 or indent < depth: ITreeContents(item)._get_public_tree_helper( l, indent + 1, depth, include_publications, filters)
def _haunt_diff(self, haunted, ghost): """diffes two containers haunted: IContainer, container to be haunted ghost: IContainer, ghost returns list of tuple: [(haunted, h_id, ghost, g_id)] whereby h_id is the haunted object's id or None if a ghost exists but no object to be haunted g_id is the ghost's id or None if the ghost doesn't exist but has to be created haunted and ghost are the objects passed in """ assert IContainer.providedBy(haunted) assert IContainer.providedBy(ghost) h_ids = list(haunted.objectIds()) g_ids = list(ghost.objectIds()) h_ids.sort() g_ids.sort() ids = [] while h_ids or g_ids: h_id = None g_id = None if h_ids: h_id = h_ids[0] if g_ids: g_id = g_ids[0] if h_id == g_id or h_id is None or g_id is None: ids.append((h_id, g_id)) if h_ids: del h_ids[0] if g_ids: del g_ids[0] elif h_id < g_id: ids.append((h_id, None)) del h_ids[0] elif h_id > g_id: ids.append((None, g_id)) del g_ids[0] return [(haunted, h_id, ghost, g_id) for (h_id, g_id) in ids]
def _get_container_tree_helper(self, l, indent, depth): for item in self.context.get_ordered_publishables(): if not IContainer.providedBy(item): continue if item.is_transparent(): l.append((indent, item)) if depth == -1 or indent < depth: ITreeContents(item)._get_container_tree_helper( l, indent + 1, depth) else: l.append((indent, item))
def _get_status_tree_helper(self, l, indent, depth): default = self.context.get_default() if default is not None: l.append((indent, default)) for item in self.context.get_ordered_publishables(): l.append((indent, item)) if not IContainer.providedBy(item): continue if (depth == -1 or indent < depth) and item.is_transparent(): ITreeContents(item)._get_status_tree_helper(l, indent+1, depth)
def _get_tree_helper(self, l, indent, depth): for item in self.context.get_ordered_publishables(): if item.getId() == 'index': # default document should not be inserted continue if (IContainer.providedBy(item) and item.is_transparent()): l.append((indent, item)) if depth == -1 or indent < depth: ITreeContents(item)._get_tree_helper(l, indent + 1, depth) else: l.append((indent, item))
def export_content(self): for content in self.settings.get_contents(): if IContainer.providedBy(content): continue viewable = content.get_viewable() if viewable is not None: self.archive.writestr( self.get_archive_name(content), getMultiAdapter( (content, HTMLExportRequest(content, self.settings)), name='index.html')().encode('utf-8')) self.references.extend(self.get_references(viewable))
def _get_status_tree_helper(self, l, indent, depth): default = self.context.get_default() if default is not None: l.append((indent, default)) for item in self.context.get_ordered_publishables(): l.append((indent, item)) if not IContainer.providedBy(item): continue if (depth == -1 or indent < depth) and item.is_transparent(): ITreeContents(item)._get_status_tree_helper( l, indent + 1, depth)
def __call__(self, content): if IContainer.providedBy(content): path = list(content.getPhysicalPath()) + [ 'index.' + self.extension] elif IPublishable.providedBy(content): path = list(aq_parent(content).getPhysicalPath()) + [ content.getId() + '.' + self.extension] elif IAsset.providedBy(content): path = list(aq_parent(content).getPhysicalPath()) + [ content.get_filename()] else: path = content.getPhysicalPath() return '/'.join(relative_path(self._origin, path))
def register_move(target, event): if event.object != target or not IContainer.providedBy(aq_parent(target)): return if event.newParent is not None: # That was not a delete if event.oldParent is event.newParent: # This was a rename. invalidation_transaction.register_entry( target, 'update') else: # This was an add. invalidation_transaction.register_entry( target, 'add')
def unregister_source(source, event): """Remove deleted sources from the service. """ if (event.object is source and event.newName is not None and IContainer.providedBy(event.newParent)): # We are just moving or renaming the source return service = queryUtility(ICodeSourceService) if service is not None and service._installed_sources is not None: source_id = getUtility(IIntIds).register(source) if source_id in service._installed_sources: service._installed_sources.remove(source_id) service._p_changed = True
def navigation_entries(self, node, depth=0, maxdepth=None): if maxdepth is None: maxdepth = self.max_depth info = {'url': absoluteURL(node, self.request), 'title': node.get_short_title(), 'nodes': None, 'onbranch': node in self.request.PARENTS, 'current': node.aq_base == self.navigation_current} if depth < maxdepth and IContainer.providedBy(node): if ((self.only_container is not None and depth < self.only_container) or info['onbranch']): children = self.filter_entries(node.get_ordered_publishables()) info['nodes'] = list(children) return info
def register_source(source, event): """Register newly created source to the service. """ if (event.object is source and not IContainer.providedBy(event.newParent)): # The source is not added in a Silva Container so it won't be usable. return service = queryUtility(ICodeSourceService) if service is not None: source_id = getUtility(IIntIds).register(source) if service._installed_sources is None: service._installed_sources = [] if source_id not in service._installed_sources: service._installed_sources.append(source_id) service._p_changed = True
def list_toc_items(self, container, level, is_displayable): """Yield for every element in this toc. The 'depth' argument limits the number of levels, defaults to unlimited. """ filter_content = getUtility( IContentFilteringService).filter(self.request) can_recurse = self.toc_depth == -1 or level < self.toc_depth for item in filter_content(self.list_container_items( container, is_displayable)): yield (level, item) if IContainer.providedBy(item) and can_recurse: for data in self.list_toc_items(item, level + 1, is_displayable): yield data
def register_remove(target, event): if not IContainer.providedBy(aq_parent(target)): return if IRoot.providedBy(event.object): # If you delete your Silva root, we don't care about anything. return if event.oldParent is not None: if event.object is target: if event.newParent is not event.oldParent: # That was a move or a delete, but not a rename invalidation_transaction.register_entry( target, 'remove') elif event.newParent is None: # This was a recursive delete invalidation_transaction.register_entry( target, 'remove')
def run(self, root, options): try: import_root = root.restrictedTraverse(options.target) except KeyError as e: logger.error('invalid target path : %s %s', options.target, e.args[0]) exit(1) if not IContainer.providedBy(import_root): logger.error('invalid import base, not a container.') exit(1) with open(options.file, 'r') as input_archive: importer = ZipImporter( import_root, TestRequest(), {'replace_content': options.replace, 'ignore_top_level_content': options.ignore_top_level}) importer.importStream(input_archive)
def list_toc_items(self, container, level, is_displayable): """Yield for every element in this toc. The 'depth' argument limits the number of levels, defaults to unlimited. """ filter_content = getUtility(IContentFilteringService).filter( self.request) can_recurse = self.toc_depth == -1 or level < self.toc_depth for item in filter_content( self.list_container_items(container, is_displayable)): yield (level, item) if IContainer.providedBy(item) and can_recurse: for data in self.list_toc_items(item, level + 1, is_displayable): yield data
def list_toc_items(self, container, level, is_displayable, to_ignore=[]): """Yield for every element in this toc. The 'depth' argument limits the number of levels, defaults to unlimited. """ filter_content = getUtility( IContentFilteringService).filter(self.request) for item in filter_content(self.list_container_items( container, is_displayable)): if (level == 0) and item.id in to_ignore: continue yield (level, item) if IContainer.providedBy(item): for data in self.list_toc_items(item, level + 1, is_displayable): yield data
def haunt(self): """populate the the ghost folder with ghosts """ haunted = self.get_haunted() if haunted is None: return False stack = self._haunt_diff(haunted, self) errors = [] while stack: # breadth first search h_container, h_id, g_container, g_id = stack.pop(0) if h_id is None: # object was removed from haunted, so just remove it and # continue g_container.manage_delObjects([g_id]) continue h_ob = h_container._getOb(h_id) g_ob = None if g_id is not None: g_ob = g_container._getOb(g_id) try: g_ob = get_factory(h_ob)(ghost=g_ob, container=g_container, auto_delete=True, auto_publish=True).modify( h_ob, h_id).verify() except ContentError as error: errors.append(error) if IContainer.providedBy(h_ob) and g_ob is not None: stack.extend(self._haunt_diff(h_ob, g_ob)) if errors: raise ContentErrorBundle(_( u"Error while synchronizing the Ghost Folder: " u"not all its content have been updated properly."), content=self, errors=errors) return True
def render(self): to_ignore = [entry.strip() for entry in self.to_ignore.split(',')] public = not IPreviewLayer.providedBy(self.request) is_displayable = public and self.is_public_displayable or self.is_preview_displayable html = [] a_templ = '<a href="%s">%s</a>' isIndented = int(self.list_type) localRoot = getLocalSite(self.model, self.request) depth = -1 prev_depth = [-1] item = None for (depth, item) in self.list_toc_items(localRoot, 0, is_displayable, to_ignore): pd = prev_depth[-1] if pd < depth: #down one level if depth == 0 or isIndented: html.append('<ul>') prev_depth.append(depth) elif pd > depth: #up one level for i in range(pd-depth): prev_depth.pop() if isIndented: html.append('</ul></li>') elif pd == depth: #same level html.append('</li>') css_class = (IContainer.providedBy(item) and depth == 0) and ' class="topContainer"' or '' html.append('<li%s>' %css_class) title = (public and item.get_title() or item.get_title_editable()) or item.id html.append(a_templ % (absoluteURL(item, self.request), escape(title)) + self._add(item)) else: #do this when the loop is finished, to #ensure that the lists are ended properly #the last item in the list could part of a nested list (with depth 1,2,3+, etc) #so need to loop down the depth and close all open lists while depth >= 0: html.append('</li></ul>') depth -= 1 if not isIndented: html.append('</ul>') return u'\n'.join(html)
def haunt(self): """populate the the ghost folder with ghosts """ haunted = self.get_haunted() if haunted is None: return False stack = self._haunt_diff(haunted, self) errors = [] while stack: # breadth first search h_container, h_id, g_container, g_id = stack.pop(0) if h_id is None: # object was removed from haunted, so just remove it and # continue g_container.manage_delObjects([g_id]) continue h_ob = h_container._getOb(h_id) g_ob = None if g_id is not None: g_ob = g_container._getOb(g_id) try: g_ob = get_factory(h_ob)( ghost=g_ob, container=g_container, auto_delete=True, auto_publish=True).modify(h_ob, h_id).verify() except ContentError as error: errors.append(error) if IContainer.providedBy(h_ob) and g_ob is not None: stack.extend(self._haunt_diff(h_ob, g_ob)) if errors: raise ContentErrorBundle( _(u"Error while synchronizing the Ghost Folder: " u"not all its content have been updated properly."), content=self, errors=errors) return True
def search_document(self, name): if not hasattr(self.context, name): return None content = getattr(self.context, name).get_silva_object() if IContainer.providedBy(content): content = content.get_default() if content is None: return None if IPermanentRedirectLink.providedBy(content): return None version = content.get_viewable() if IGhost.providedBy(content): content = version.get_haunted() version = content.get_viewable() if version is not None: details = queryMultiAdapter((version, self.request), IDocumentDetails) if details is not None: return details.get_text() return None
def search_document(self, name): if not hasattr(self.context, name): return None content = getattr(self.context, name).get_silva_object() if IContainer.providedBy(content): content = content.get_default() if content is None: return None if IPermanentRedirectLink.providedBy(content): return None version = content.get_viewable() if IGhost.providedBy(content): content = version.get_haunted() version = content.get_viewable() if version is not None: details = queryMultiAdapter( (version, self.request), IDocumentDetails) if details is not None: return details.get_text() return None
def get_all_sources(self, item=None): catalog = getUtility(ICatalogService) brains = catalog({ 'meta_type': 'Silva News Publication', 'snn-np-settingsis_private':'no'}) if item is not None: while not IContainer.providedBy(item): item = aq_parent(item) paths = [] parts = item.getPhysicalPath() for size in range(1, len(parts) + 1): paths.append('/'.join(parts[:size])) brains += catalog({ 'snn-np-settingsis_private': 'yes', 'parent_path': paths}) return (brain.getObject() for brain in brains)
def need_update(self): if IGhostFolder.providedBy(self.manager.ghost): return self.target != self.manager.ghost.get_haunted() # Only update if the invalid ghost is an asset. return IContainer.providedBy(self.manager.ghost)
def validate(self, target, adding=False): error = super(GhostFolderManager, self).validate(target, adding) if error is None: if not IContainer.providedBy(target): return ContainerInvalidTarget() return error
def is_transparent(self): """show in subtree? depends on haunted object""" content = self.get_haunted() if IContainer.providedBy(content): return content.is_transparent() return 0
def validate(self, content): return (hasattr(aq_base(content), '__subscribability__') and (IContent.providedBy(content) or IContainer.providedBy(content)))