def __init__(self, context, request, tz=None): self.context = context self.request = request self.tz = tz self.repo = find_repo(context) self.profiles = find_profiles(context) self.deleted_branch = None self.container_id = context.docid self.error = None self.deleted = [] self.subfolder_path = [] self.can_shred = has_permission(MODERATE, context, request) subfolder = self.request.params.get('subfolder') if subfolder: try: path = decode_trash_path(subfolder) for name, container_id, deleted_item in traverse_trash( self.context, path): if deleted_item is not None: self.deleted_branch = deleted_item self.container_id = container_id self.subfolder_path.append((name, container_id)) except (ValueError, TypeError), e: log.exception("Invalid trash subfolder: %s", subfolder) self.error = e
def evolve(site): """ Initialize repozitory. """ repo = find_repo(site) if repo is not None: init_repozitory(repo, site)
def show_trash(context, request): repo = find_repo(context) profiles = find_profiles(context) def display_record(record): deleted_by = profiles[record.deleted_by] version = repo.history(record.docid, only_current=True)[0] return { 'date': format_local_date(record.deleted_time), 'deleted_by': { 'name': deleted_by.title, 'url': model_url(deleted_by, request), }, 'restore_url': model_url( context, request, 'restore', query={'docid': str(record.docid), 'name': record.name}), 'title': version.title, } try: contents = repo.container_contents(context.docid) deleted = contents.deleted except: deleted = [] return { 'api': TemplateAPI(context, request, 'Trash'), 'deleted': map(display_record, deleted), }
def preview_wikipage_view(context, request, WikiPage=WikiPage): version_num = int(request.params['version_num']) repo = find_repo(context) for version in repo.history(context.docid): if version.version_num == version_num: break else: raise NotFound("No such version: %d" % version_num) page = WikiPage() page.__parent__ = context.__parent__ page.revert(version) is_front_page = (context.__name__ == 'front_page') if is_front_page: community = find_interface(context, ICommunity) page_title = '%s Community Wiki Page' % community.title else: page_title = page.title profiles = find_profiles(context) author = profiles[version.user] # Extra paranoia, probably not strictly necessary. I just want to make # extra special sure that the temp WikiPage object we create above # doesn't accidentally get attached to the persistent object graph. transaction.doom() return { 'date': format_local_date(version.archive_time), 'author': author.title, 'title': page_title, 'body': page.cook(request), }
def traverse_subfolders(context, subfolder_path): """Yield (docid, exists) for each element in a JSON subfolder path. Raises ValueError if the path is not valid. """ if not subfolder_path: return repo = find_repo(context) parts = json.loads(subfolder_path) # May raise ValueError container_id = context.docid for name, docid in parts: docid = int(docid) try: contents = repo.container_contents(container_id) except NoResultFound: raise ValueError("Document %d is not a container." % container_id) if contents.map.get(name) == docid: yield docid, True container_id = docid continue for item in contents.deleted: if item.name == name and item.docid == docid: yield docid, False break else: raise ValueError("Subfolder %s (docid %d) not found in trash." % (repr(name), docid))
def add_to_repo(obj, event): """ Add a newly created object to the version repository. Intended use is as an IObjectAddedEvent subscriber. """ if find_interface(obj, IIntranets): # Exclude /offices from repo return repo = find_repo(obj) if repo is None: return if not repo.history(obj.docid, True): # It is not in the repo, so add it adapter = queryAdapter(obj, IObjectVersion) if adapter is not None: if adapter.comment is None: adapter.comment = 'Content created.' repo.archive(adapter) container = event.parent adapter = queryAdapter(container, IContainerVersion) if adapter is not None: request = get_current_request() user = authenticated_userid(request) repo.archive_container(adapter, user) # Recurse into children if adding a subtree if IFolder.providedBy(obj): for name, child in obj.items(): fake_event = FakeEvent() fake_event.parent = obj add_to_repo(child, fake_event)
def add_to_repo(obj, event): """ Add a newly created object to the version repository. Intended use is as an IObjectAddedEvent subscriber. """ repo = find_repo(obj) if repo is None: return try: # If we're undeleting an object, it might already be in the repo repo.history(obj.docid) except: # It is not in the repo, so add it adapter = queryAdapter(obj, IObjectVersion) if adapter is not None: if adapter.comment is None: adapter.comment = 'Content created.' repo.archive(adapter) container = event.parent adapter = queryAdapter(container, IContainerVersion) if adapter is not None: request = get_current_request() user = authenticated_userid(request) repo.archive_container(adapter, user) # Recurse into children if adding a subtree if IFolder.providedBy(obj): for name, child in obj.items(): fake_event = FakeEvent() fake_event.parent = obj add_to_repo(child, fake_event)
def undelete(context, request): repo = find_repo(context) docid = int(request.params['docid']) name = request.params['name'] doc = _undelete(repo, context, docid, name) repo.archive_container(IContainerVersion(context), authenticated_userid(request)) index_content(context, None) return HTTPFound(location=model_url(doc, request))
def show_trash(context, request, tz=None): repo = find_repo(context) profiles = find_profiles(context) def display_deleted_item(docid, deleted_item, is_container): version = repo.history(docid, only_current=True)[0] if is_container: url = resource_url(context, request, 'trash', query={ 'subfolder': str(docid)}) else: url = None if deleted_item: deleted_by = profiles[deleted_item.deleted_by] return { 'date': format_local_date(deleted_item.deleted_time, tz), 'deleted_by': { 'name': deleted_by.title, 'url': resource_url(deleted_by, request), }, 'restore_url': resource_url( context, request, 'restore', query={'docid': str(deleted_item.docid), 'name': deleted_item.name}), 'title': version.title, 'url': url} else: return { 'date': None, 'deleted_by': None, 'restore_url': None, 'title': version.title, 'url': url} subfolder = request.params.get('subfolder') if not subfolder: subfolder = context.docid contents = repo.container_contents(subfolder) deleted = [] contents_deleted = contents.deleted deleted_container_children = set(repo.filter_container_ids( item.docid for item in contents_deleted)) for item in contents_deleted: is_container = item.docid in deleted_container_children deleted.append(display_deleted_item(item.docid, item, is_container)) for docid in repo.which_contain_deleted(contents.map.values()): deleted.append(display_deleted_item(docid, None, True)) deleted.sort(key=lambda x: x['title']) return { 'api': TemplateAPI(context, request, 'Trash'), 'deleted': deleted, }
def main(argv=sys.argv): parser = create_karl_argparser(description="Change creator of content.") parser.add_argument('--batch-size', type=int, default=500, help='Number of objects to initialize per transaction.') args = parser.parse_args(argv[1:]) env = args.bootstrap(args.config_uri) root, closer = env['root'], env['closer'] repo = find_repo(root) if repo is None: args.parser.error("No repository is configured.") init_repozitory(repo, root, args.batch_size) closer()
def add_to_repo(obj, event, update_container=True): """ Add a newly created object to the version repository. Intended use is as an IObjectAddedEvent subscriber. """ if find_interface(obj, IIntranets): # Exclude /offices from repo return repo = find_repo(obj) if repo is None: return if not repo.history(obj.docid, True): # It is not in the repo, so add it adapter = queryAdapter(obj, IObjectVersion) if adapter is not None: if adapter.comment is None: adapter.comment = 'Content created.' repo.archive(adapter) blobs = getattr(adapter, 'blobs', None) if blobs: for blob in adapter.blobs.values(): blob.close() if update_container: container = event.parent adapter = queryAdapter(container, IContainerVersion) if adapter is not None: # In some cases, a sibling might not have been added to the archive # yet. Archiving the container before all of its children are # archived can result in an integrity constraint violation, so we # should check for this case and handle it. for name, docid in adapter.map.items(): if docid == obj.docid: continue if not repo.history(docid, True): orphan = container[name] log.warn("Adding object to archive: %s" % resource_path(orphan)) add_to_repo(orphan, event, update_container=False) request = get_current_request() user = authenticated_userid(request) repo.archive_container(adapter, user) # Recurse into children if adding a subtree if IFolder.providedBy(obj): for name, child in obj.items(): fake_event = FakeEvent() fake_event.parent = obj add_to_repo(child, fake_event)
def revert(context, request): repo = find_repo(context) version_num = int(request.params['version_num']) for version in repo.history(context.docid): if version.version_num == version_num: break else: raise ValueError('No such version: %d' % version_num) context.revert(version) repo.reverted(context.docid, version_num) catalog = find_catalog(context) catalog.reindex_doc(context.docid, context) return HTTPFound(location=resource_url(context, request))
def show_wikipage_view(context, request): layout = request.layout_manager.layout is_front_page = (context.__name__ == 'front_page') if is_front_page: community = find_interface(context, ICommunity) layout.page_title = '%s Community Wiki Page' % community.title backto = False else: layout.page_title = context.title backto = { 'href': resource_url(context.__parent__, request), 'title': context.__parent__.title, } actions = [] if has_permission('edit', context, request): actions.append(('Edit', resource_url(context, request, 'edit.html'))) if has_permission('delete', context, request) and not is_front_page: actions.append(('Delete', resource_url(context, request, 'delete.html'))) repo = find_repo(context) show_trash = False if not find_interface(context, IIntranets): if repo is not None and has_permission('edit', context, request): actions.append( ('History', resource_url(context, request, 'history.html'))) show_trash = True if has_permission('administer', context, request): actions.append( ('Advanced', resource_url(context, request, 'advanced.html'))) api = TemplateAPI(context, request, layout.page_title) client_json_data = dict(tagbox=get_tags_client_data(context, request), ) panel_data = layout.head_data['panel_data'] panel_data['tagbox'] = client_json_data['tagbox'] layout.add_portlet('recent_activity') wiki = find_interface(context, IWiki) feed_url = resource_url(wiki, request, "atom.xml") return dict( api=api, actions=actions, head_data=convert_to_script(client_json_data), feed_url=feed_url, backto=backto, is_front_page=is_front_page, show_trash=show_trash, lock_info=lock.lock_info_for_view(context, request), )
def show_wikipage_view(context, request): layout = request.layout_manager.layout is_front_page = (context.__name__ == 'front_page') if is_front_page: community = find_interface(context, ICommunity) layout.page_title = '%s Community Wiki Page' % community.title backto = False else: layout.page_title = context.title backto = { 'href': resource_url(context.__parent__, request), 'title': context.__parent__.title, } actions = [] if has_permission('edit', context, request): actions.append(('Edit', resource_url(context, request, 'edit.html'))) if has_permission('delete', context, request) and not is_front_page: actions.append(('Delete', resource_url(context, request, 'delete.html'))) repo = find_repo(context) show_trash = False if not find_interface(context, IIntranets): if repo is not None and has_permission('edit', context, request): actions.append(('History', resource_url(context, request, 'history.html'))) show_trash = True if has_permission('administer', context, request): actions.append(('Advanced', resource_url(context, request, 'advanced.html'))) api = TemplateAPI(context, request, layout.page_title) client_json_data = dict( tagbox = get_tags_client_data(context, request), ) panel_data = layout.head_data['panel_data'] panel_data['tagbox'] = client_json_data['tagbox'] layout.add_portlet('recent_activity') wiki = find_interface(context, IWiki) feed_url = resource_url(wiki, request, "atom.xml") return dict( api=api, actions=actions, head_data=convert_to_script(client_json_data), feed_url=feed_url, backto=backto, is_front_page=is_front_page, show_trash=show_trash, lock_info=lock.lock_info_for_view(context, request), )
def delete_in_repo(obj, event): """ Add object to deleted items in repozitory. Intended use is as an IObjectRemovedEvent subscriber. """ container = event.parent repo = find_repo(container) if repo is not None: adapter = queryAdapter(container, IContainerVersion) if adapter is not None: request = get_current_request() user = authenticated_userid(request) repo.archive_container(adapter, user)
def show_history(context, request, tz=None): repo = find_repo(context) profiles = find_profiles(context) # downloading files using ajax shows information bar in IE # We need to disable that if context is a file use_ajax = True preview_view = 'preview.html' if ICommunityFile.providedBy(context): use_ajax = False preview_view = 'download_preview' def display_record(record): editor = profiles[record.user] return { 'date': format_local_date(record.archive_time, tz), 'editor': { 'name': editor.title, 'url': resource_url(editor, request), }, 'preview_url': resource_url(context, request, preview_view, query={'version_num': str(record.version_num)}), 'restore_url': resource_url(context, request, 'revert', query={'version_num': str(record.version_num)}), 'is_current': record.current_version == record.version_num, } # newest to oldest history = map(display_record, repo.history(context.docid)) page_title = 'History for %s' % context.title backto = {'href': resource_url(context, request), 'title': context.title} return { 'api': TemplateAPI(context, request, page_title), 'history': history, 'use_ajax': use_ajax, 'backto': backto, 'lock_info': lock_info_for_view(context, request), }
def add_to_repo(obj, event, update_container=True): """ Add a newly created object to the version repository. Intended use is as an IObjectAddedEvent subscriber. """ repo = find_repo(obj) if repo is None: return if not repo.history(obj.docid, True): # It is not in the repo, so add it adapter = queryAdapter(obj, IObjectVersion) if adapter is not None: if adapter.comment is None: adapter.comment = 'Content created.' repo.archive(adapter) blobs = getattr(adapter, 'blobs', None) if blobs: for blob in adapter.blobs.values(): blob.close() if update_container: container = event.parent adapter = queryAdapter(container, IContainerVersion) if adapter is not None: # In some cases, a sibling might not have been added to the archive # yet. Archiving the container before all of its children are # archived can result in an integrity constraint violation, so we # should check for this case and handle it. for name, docid in adapter.map.items(): if docid == obj.docid: continue if not repo.history(docid, True): orphan = container[name] log.warn("Adding object to archive: %s" % resource_path(orphan)) add_to_repo(orphan, event, update_container=False) request = get_current_request() user = authenticated_userid(request) repo.archive_container(adapter, user) # Recurse into children if adding a subtree if IFolder.providedBy(obj): for name, child in obj.items(): fake_event = FakeEvent() fake_event.parent = obj add_to_repo(child, fake_event)
def show_wikipage_view(context, request): is_front_page = (context.__name__ == 'front_page') if is_front_page: community = find_interface(context, ICommunity) page_title = '%s Community Wiki Page' % community.title backto = False else: page_title = context.title backto = { 'href': model_url(context.__parent__, request), 'title': context.__parent__.title, } actions = [] if has_permission('edit', context, request): actions.append(('Edit', 'edit.html')) if has_permission('delete', context, request) and not is_front_page: actions.append(('Delete', 'delete.html')) repo = find_repo(context) if repo is not None and has_permission('edit', context, request): actions.append(('History', 'history.html')) show_trash = True else: show_trash = False if has_permission('administer', context, request): actions.append(('Advanced', 'advanced.html')) api = TemplateAPI(context, request, page_title) client_json_data = convert_to_script(dict( tagbox = get_tags_client_data(context, request), )) wiki = find_interface(context, IWiki) feed_url = model_url(wiki, request, "atom.xml") return dict( api=api, actions=actions, head_data=client_json_data, feed_url=feed_url, backto=backto, is_front_page=is_front_page, show_trash=show_trash, lock_info=lock.lock_info_for_view(context, request), )
def show_trash(context, request, tz=None): repo = find_repo(context) profiles = find_profiles(context) def display_deleted_item(docid, tree_node): deleted_item = tree_node.deleted_item version = repo.history(docid, only_current=True)[0] if tree_node: url = resource_url(context, request, 'trash', query={ 'subfolder': str(docid)}) else: url = None if deleted_item: deleted_by = profiles[deleted_item.deleted_by] return { 'date': format_local_date(deleted_item.deleted_time, tz), 'deleted_by': { 'name': deleted_by.title, 'url': resource_url(deleted_by, request), }, 'restore_url': resource_url( context, request, 'restore', query={'docid': str(deleted_item.docid), 'name': deleted_item.name}), 'title': version.title, 'url': url} else: return { 'date': None, 'deleted_by': None, 'restore_url': None, 'title': version.title, 'url': url} trash = generate_trash_tree(repo, context.docid) subfolder = request.params.get('subfolder') if subfolder: trash = trash.find(int(subfolder)) deleted = [display_deleted_item(docid, trash[docid]) for docid, item in trash.items()] deleted.sort(key=lambda x: x['title']) return { 'api': TemplateAPI(context, request, 'Trash'), 'deleted': deleted, }
def show_history(context, request, tz=None): repo = find_repo(context) profiles = find_profiles(context) # downloading files using ajax shows information bar in IE # We need to disable that if context is a file use_ajax = True preview_view = 'preview.html' if ICommunityFile.providedBy(context): use_ajax = False preview_view = 'download_preview' def display_record(record): editor = profiles[record.user] return { 'date': format_local_date(record.archive_time, tz), 'editor': { 'name': editor.title, 'url': resource_url(editor, request), }, 'preview_url': resource_url( context, request, preview_view, query={'version_num': str(record.version_num)}), 'restore_url': resource_url( context, request, 'revert', query={'version_num': str(record.version_num)}), 'is_current': record.current_version == record.version_num, } # newest to oldest history = map(display_record, repo.history(context.docid)) page_title = 'History for %s' % context.title backto = { 'href': resource_url(context, request), 'title': context.title } return { 'api': TemplateAPI(context, request, page_title), 'history': history, 'use_ajax': use_ajax, 'backto': backto, 'lock_info': lock_info_for_view(context, request), }
def set_modified(obj, event): """ Set the modified date on a single piece of content. This subscriber is non-recursive. Intended use is as an IObjectModified event subscriber. """ if is_content(obj): now = _now() obj.modified = now _modify_community(obj, now) repo = find_repo(obj) if repo is not None: adapter = queryAdapter(obj, IObjectVersion) if adapter is not None: repo.archive(adapter) if adapter.comment is None: adapter.comment = 'Content modified.'
def shred(context, request): repo = find_repo(context) path = decode_trash_path(request.params['path']) _name, docid, _item = list(traverse_trash(context, path))[-1] docids = set([docid]) # If the object is a container, shred a subtree. for contents in repo.iter_hierarchy(docid, follow_deleted=True, follow_moved=False): docids.update(contents.map.values()) for item in contents.deleted: if not item.new_container_ids: docids.add(item.docid) container_ids = repo.filter_container_ids(docids) repo.shred(docids, container_ids) return HTTPFound(location=resource_url(context, request, '@@trash', query={ 'path': encode_trash_path(path[:-1]), }))
def show_wikitoc_view(context, request): is_front_page = (context.__name__ == 'front_page') if is_front_page: community = find_interface(context, ICommunity) page_title = '%s Community Wiki Page' % community.title backto = False else: page_title = context.title backto = { 'href': resource_url(context.__parent__, request), 'title': context.__parent__.title, } actions = [] api = TemplateAPI(context, request, page_title) wikitoc_data = get_wikitoc_data(context, request) page_data = dict( wikitoc = wikitoc_data, ) # ... for ux1 client_json_data = convert_to_script(page_data) # ... for ux2 request.layout_manager.layout.head_data['page_data'] = page_data wiki = find_interface(context, IWiki) feed_url = resource_url(wiki, request, "atom.xml") repo = find_repo(context) show_trash = repo is not None and has_permission('edit', context, request) return dict(api=api, actions=actions, head_data=client_json_data, feed_url=feed_url, backto=backto, lock_info=lock.lock_info_for_view(context, request), show_trash=show_trash, )
def show_wikitoc_view(context, request): is_front_page = (context.__name__ == 'front_page') if is_front_page: community = find_interface(context, ICommunity) page_title = '%s Community Wiki Page' % community.title backto = False else: page_title = context.title backto = { 'href': resource_url(context.__parent__, request), 'title': context.__parent__.title, } actions = [] api = TemplateAPI(context, request, page_title) wikitoc_data = get_wikitoc_data(context, request) page_data = dict(wikitoc=wikitoc_data, ) # ... for ux1 client_json_data = convert_to_script(page_data) # ... for ux2 request.layout_manager.layout.head_data['page_data'] = page_data wiki = find_interface(context, IWiki) feed_url = resource_url(wiki, request, "atom.xml") repo = find_repo(context) show_trash = repo is not None and has_permission('edit', context, request) return dict( api=api, actions=actions, head_data=client_json_data, feed_url=feed_url, backto=backto, lock_info=lock.lock_info_for_view(context, request), show_trash=show_trash, )
def show_history(context, request): repo = find_repo(context) profiles = find_profiles(context) def display_record(record): editor = profiles[record.user] return { 'date': format_local_date(record.archive_time), 'editor': { 'name': editor.title, 'url': model_url(editor, request), }, 'preview_url': model_url( context, request, 'preview.html', query={'version_num': str(record.version_num)}), 'restore_url': model_url( context, request, 'revert', query={'version_num': str(record.version_num)}), 'is_current': record.current_version == record.version_num, } try: history = repo.history(context.docid) except: history = [] history = map(display_record, history) history.reverse() page_title = 'History for %s' % context.title backto = { 'href': model_url(context, request), 'title': context.title } return { 'api': TemplateAPI(context, request, page_title), 'history': history, 'backto': backto, 'lock_info': lock_info_for_view(context, request), }
def undelete(context, request): repo = find_repo(context) path = decode_trash_path(request.params['path']) parent = context for name, docid, _ in traverse_trash(context, path): try: doc = parent[name] except KeyError: doc = None if doc is None or doc.docid != docid: # Restore this item. doc = _restore(repo, parent, docid, name) repo.archive_container(IContainerVersion(parent), authenticated_userid(request)) index_content(parent, None) parent = doc # If the user undeleted a container, restore everything it contained. _restore_subtree(repo, parent, request) return HTTPFound(location=resource_url(parent, request))
def traverse_trash(context, path): """Yield (name, docid, deleted_item or None) for elements in a trash path. A trash path is a list of (name, docid) pairs. The docid of each path segment can be None, causing the path to be ambiguous; this function will react by choosing the first match it finds. Raises ValueError if an element of the path is not found or is not valid. The ValueError may indicate a security violation attempt, since invalid trash paths could be a way to expose sensitive info. """ repo = find_repo(context) container_id = context.docid for name, docid in path: try: contents = repo.container_contents(container_id) except NoResultFound: raise ValueError("Document %d is not a container." % container_id) if docid is not None: docid = int(docid) else: docid = contents.map.get(name) if contents.map.get(name) == docid: yield name, docid, None container_id = docid continue for item in contents.deleted: if (item.name == name and (docid is None or item.docid == docid) and not item.new_container_ids): yield name, item.docid, item container_id = item.docid break else: raise ValueError("Subfolder not found in trash: %s (docid %s)" % (name, docid))
def show_wikitoc_view(context, request): is_front_page = (context.__name__ == 'front_page') if is_front_page: community = find_interface(context, ICommunity) page_title = '%s Community Wiki Page' % community.title backto = False else: page_title = context.title backto = { 'href': model_url(context.__parent__, request), 'title': context.__parent__.title, } actions = [] api = TemplateAPI(context, request, page_title) wikitoc_data = get_wikitoc_data(context, request) client_json_data = convert_to_script(dict( wikitoc = wikitoc_data, )) wiki = find_interface(context, IWiki) feed_url = model_url(wiki, request, "atom.xml") repo = find_repo(context) show_trash = repo is not None and has_permission('edit', context, request) return render_template_to_response( 'templates/show_wikitoc.pt', api=api, actions=actions, head_data=client_json_data, feed_url=feed_url, backto=backto, show_trash=show_trash, )
def undelete(context, request): repo = find_repo(context) docid = int(request.params['docid']) name = request.params['name'] # Find parent folder to restore file into trash = generate_trash_tree(repo, context.docid) parent = context for child_docid in trash.paths[docid][:-1]: for child in parent.values(): if child.docid == child_docid: next_parent = child break else: # Need to restore a folder in order to place file in proper place # in tree. container = repo.container_contents(parent.docid) for deleted_item in container.deleted: if deleted_item.docid == child_docid: next_parent = _undelete(repo, parent, child_docid, deleted_item.name, False) repo.archive_container(IContainerVersion(parent), authenticated_userid(request)) break else: #pragma NO COVERAGE # Will only get here in case of programmer error or db # corruption (due to programmer error) raise RuntimeError("Cannot find container to restore: %d" % child_docid) parent = next_parent doc = _undelete(repo, parent, docid, name, True) repo.archive_container(IContainerVersion(parent), authenticated_userid(request)) index_content(parent, None) return HTTPFound(location=resource_url(parent, request))
def main(args): site, closer = args.get_root(args.inst) repo = find_repo(site) if repo is None: args.parser.error("No repository is configured.") init_repozitory(repo, site, args.batch_size)
def main(args): site, closer = args.get_root(args.inst) repo = find_repo(site) if repo is not None: init_repo(repo, site) transaction.commit()
def test_find_repo(self): from karl.utils import find_repo context = testing.DummyModel() self.assertEqual(find_repo(context), None) context.repo = '1' self.assertEqual(find_repo(context), '1')