Ejemplo n.º 1
0
 def isReport(self, name):
     """ See IMailinDispatcher.
     """
     root = find_root(self.context)
     if name in root.list_aliases:
         return True
     pd = find_peopledirectory(self.context)
     tokens = name.split('+')
     try:
         find_model(pd, tokens)
     except KeyError:
         return False
     return True
Ejemplo n.º 2
0
def user_tagged_content(event):
    if ITagAddedEvent.providedBy(event):
        request = get_current_request()
        context = getattr(request, 'context', None)
        if context is None:
            return
        events = find_events(context)
        if not events:
            return
        site = find_site(context)
        catalog = find_catalog(context)
        path = catalog.document_map.address_for_docid(event.item)
        tagged = find_model(site, path)
        if tagged is None:
            return
        profile_id = event.user
        if profile_id in (None, 'None'):
            return
        profile = site['profiles'][profile_id]
        info = _getInfo(profile, tagged)
        if info is None:
            return
        if info['content_type'] == 'Community':
            info['flavor'] = 'tagged_community'
        elif info['content_type'] == 'Profile':
            info['flavor'] = 'tagged_profile'
        else:
            info['flavor'] = 'tagged_other'
        info['operation'] = 'tagged'
        info['tagname'] = event.name
        events.push(**info)
Ejemplo n.º 3
0
    def createContent(self, name, content_type, obj_location, REQUEST,
                      **kwargs):
        """ """

        if isinstance(content_type, basestring):
            klass = self.get_model(content_type)
        else:
            klass = content_type

        if type(obj_location) == str:
            obj_location = find_model(self, obj_location)

        newobj = klass(name=name)
        newobj.put()
        # Hook content up to traveral machinery locations etc.. before
        # applying all the data
        if IContentish.providedBy(newobj):
            if obj_location:
                obj_location.addContent(newobj, name, REQUEST)
                zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(self))
                self.setcached(str(obj_location.getPath()), None)
        elif isinstance(newobj, NonContentishMixin):
            newobj.__parent__ = obj_location

        newobj.applyChanges(kwargs)
        newobj.put()

        return newobj
Ejemplo n.º 4
0
    def checkPermission(self, info):
        """ Does user have permission to author content in the given context?

        Uses ACL security policy to test.
        """
        users = find_users(self.context)
        for target in info['targets']:
            if 'error' in target:
                continue
            report_name = target.get('report')
            if report_name is not None:
                pd = find_peopledirectory(self.context)
                context = find_model(pd, report_name.split('+'))
                permission = "email"
            else:
                communities = find_communities(self.context)
                community = communities[target['community']]
                context = community[target['tool']]
                permission = "create"   # XXX In theory could depend on target
            user = users.get_by_id(info['author'])
            if user is not None:
                user = dict(user)
                user['repoze.who.userid'] = info['author']

            # BFG Security API always assumes http request, so we fabricate a
            # fake request.
            request = webob.Request.blank('/')
            request.environ['repoze.who.identity'] = user

            if not has_permission(permission, context, request):
                target['error'] = 'Permission Denied'
Ejemplo n.º 5
0
    def process_message(self, message, info, target, text, attachments):
        report_name = target.get('report')
        if report_name is not None:
            pd = find_peopledirectory(self.root)
            context = find_model(pd, report_name.split('+'))
        else:
            community = find_communities(self.root)[target['community']]
            context = tool = community[target['tool']]

            if target['in_reply_to'] is not None:
                docid = int(hex_to_docid(target['in_reply_to']))
                catalog = find_catalog(context)
                path = catalog.document_map.address_for_docid(docid)
                item = find_model(self.root, path)
                context = item

        IMailinHandler(context).handle(message, info, text, attachments)
Ejemplo n.º 6
0
 def __call__(self, v):
     if not v:
         return
     site = find_site(self.context)
     try:
         target = find_model(site, v)
     except KeyError, e:
         raise Invalid("Path not found: %s" % v)
Ejemplo n.º 7
0
def move_content_view(context, request):
    """
    Move content from one community to another.  Only blog entries supported
    for now.  May or may not eventually expand to other content types.
    """
    api = AdminTemplateAPI(context, request, 'Admin UI: Move Content')
    filtered_content = []

    if 'filter_content' in request.params:
        # We're limiting ourselves to content that always lives in the same
        # place in each community, ie /blog, /calendar, /wiki, etc, so that
        # we can be pretty sure we can figure out where inside the destination
        # community we should move it to.
        filtered_content = _get_filtered_content(
            context, request, [IBlogEntry, IWikiPage, ICalendarEvent])
        if not filtered_content:
            api.error_message = 'No content matches your query.'

    if 'move_content' in request.params:
        to_community = request.params.get('to_community', '')
        if not to_community:
            api.error_message = 'Please specify destination community.'
        else:
            try:
                paths = request.params.getall('selected_content')
                dst_community = find_model(context, to_community)
                for path in paths:
                    obj = find_model(context, path)
                    dst_container = _find_dst_container(obj, dst_community)
                    name = make_unique_name(dst_container, obj.__name__)
                    del obj.__parent__[obj.__name__]
                    dst_container[name] = obj

                if len(paths) == 1:
                    status_message = 'Moved one content item.'
                else:
                    status_message = 'Moved %d content items.' % len(paths)

                redirect_to = model_url(
                    context, request, request.view_name,
                    query=dict(status_message=status_message)
                )
                return HTTPFound(location=redirect_to)
            except _DstNotFound, error:
                api.error_message = str(error)
Ejemplo n.º 8
0
 def resolver(docid):
     path = address(docid)
     if path is None:
         return None
     try:
         return find_model(self.context, path)
     except KeyError:
         logger and logger.warn('Model missing: %s' % path)
         return None
Ejemplo n.º 9
0
    def processMessage(self, message, info, text, attachments):
        report_name = info.get('report')
        if report_name is not None:
            pd = find_peopledirectory(self.root)
            target = find_model(pd, report_name.split('+'))
        else:
            community = find_communities(self.root)[info['community']]
            target = tool = community[info['tool']]

            # XXX this should be more like:
            if info['in_reply_to'] is not None:
                docid = int(hex_to_docid(info['in_reply_to']))
                catalog = find_catalog(target)
                path = catalog.document_map.address_for_docid(docid)
                item = find_model(self.root, path)
                target = item

        IMailinHandler(target).handle(message, info, text, attachments)
Ejemplo n.º 10
0
 def __call__(self, docid):
     site = self.context.site
     catalog = find_catalog(site)
     if catalog is None:
         raise ValueError('No catalog')
     path = catalog.document_map.address_for_docid(docid)
     if path is None:
         raise KeyError(docid)
     doc = find_model(site, path)
     community = find_community(doc)
     return community and community.__name__ or None
Ejemplo n.º 11
0
    def processMessage(self, message, info, text, attachments):
        community = find_communities(self.root)[info["community"]]
        target = tool = community[info["tool"]]

        # XXX this should be more like:
        if info["in_reply_to"] is not None:
            docid = int(hex_to_docid(info["in_reply_to"]))
            catalog = find_catalog(target)
            path = catalog.document_map.address_for_docid(docid)
            item = find_model(self.root, path)
            target = item

        IMailinHandler(target).handle(message, info, text, attachments)
Ejemplo n.º 12
0
def _get_portlet_html(context, request, portlet_ids):
    missing = '<div class="sections"><p>Missing portlet at %s</p></div>'
    html = ''
    for portlet_id in portlet_ids:
        try:
            model = find_model(context, portlet_id)
        except KeyError:
            html += missing % portlet_id
            continue
        portlet_info = getMultiAdapter((model, request), IIntranetPortlet)
        html += portlet_info.asHTML

    return html
Ejemplo n.º 13
0
def _get_calendar_layers(context):
    layers = [ x for x in context.values() if ICalendarLayer.providedBy(x) ]
    for layer in layers:
        layer._v_categories = []
        for path in layer.paths:
            category = {}
            try:
                calendar = find_model(context, path)
                title = _calendar_category_title(calendar)
                category['title'] = title
                layer._v_categories.append(category)
            except KeyError:
                continue
    return layers
Ejemplo n.º 14
0
def prune_catalog(root, out=None):
    """
    Under some circumstances (an error of some sort) we can wind up with
    documents in the catalog that no longer exist in real life.  This prunes
    the catalog of dead records.
    """
    catalog = find_catalog(root)
    for path, docid in list(catalog.document_map.address_to_docid.items()):
        try:
            model = find_model(root, path)
        except KeyError:
            if out is not None:
                print >>out, "Removing dead catalog record: %s" % path
            catalog.unindex_doc(docid)
            catalog.document_map.remove_docid(docid)
Ejemplo n.º 15
0
def evolve(site):
    """
    Add the new containment index to the catalog.
    """
    catalog = find_catalog(site)
    if 'containment' in catalog:
        print 'Nothing to do.'
        return

    index = CatalogKeywordIndex(get_containment)
    catalog['containment'] = index
    for docid, address in catalog.document_map.docid_to_address.items():
        print 'Indexing containment: %s' % address
        model = find_model(site, address)
        index.index_doc(docid, model)
        model._p_deactivate()
Ejemplo n.º 16
0
    def validate_python(self, value, state):
        super(HomePath, self).validate_python(value, state)

        context = getattr(state, "context", None)
        if value and context:
            site = find_site(context)
            try:
                target = find_model(site, value)
            except KeyError, e:
                raise Invalid(
                    "Path not found: %s" % value,
                    value, state)
            else:
                if target is site:
                    raise Invalid(
                        "Home path must not point to the site root",
                        value, state)
Ejemplo n.º 17
0
def _get_portlet_html(context, request, portlet_ids):
    missing = '<div class="generic-portlet"><p>Missing portlet at %s</p></div>'
    notaportlet = '<div class="sections"><p>%s is not a portlet</p></div>'
    html = ""
    for portlet_id in portlet_ids:
        try:
            model = find_model(context, portlet_id)
        except KeyError:
            html += missing % portlet_id
            continue
        try:
            portlet_info = getMultiAdapter((model, request), IIntranetPortlet)
        except ComponentLookupError:
            html += notaportlet % portlet_id
            continue
        html += portlet_info.asHTML

    return html
Ejemplo n.º 18
0
def evolve(root):
    """
    We've added a modified_by index to the catalog to support renaming of
    users and reassignment of content from one user to another.  Without the
    index we'd have to walk the entire content tree in order to update
    modified_by attributes on documents.
    """
    print "Adding the 'modified_by' index to the catalog."
    root.update_indexes()
    catalog = find_catalog(root)
    index = catalog["modified_by"]
    entries = list(catalog.document_map.docid_to_address.items())
    n_docs = len(entries)
    for n, (docid, addr) in enumerate(entries):
        if n % 500 == 0:
            print "Indexed %d/%d documents" % (n, n_docs)
        doc = find_model(root, addr)
        index.index_doc(docid, doc)
        doc._p_deactivate()
Ejemplo n.º 19
0
def evolve(context):
    catalog = find_catalog(context)
    index = catalog['texts']
    for docid in index.index._docweight.keys():
        try:
            path = catalog.document_map.address_for_docid(docid)
            context = find_model(context, path)
            if (ICalendarLayer.providedBy(context) or
                ICalendarCategory.providedBy(context) or
                not IContent.providedBy(context)):
                index.unindex_doc(docid)

            if hasattr(context, '_p_deactivate'):
                context._p_deactivate()
        except KeyError:
            # Work around some bad data in the db--some calendar categories
            # got added with '/' characters in their ids.  Skip them for now
            # until we can figure out what to do with them.
            print "Bad path in catalog: ", path
Ejemplo n.º 20
0
def community_tag_users_view(context, request):
    page_title = 'Tag Users'
    api = request.api
    api.page_title = page_title

    tag = request.params.get('tag', None)
    docid = request.params.get('docid', None)
    # Test for some cases
    if tag is None:
        return HTTPBadRequest('Missing parameter for tag')
    if docid is None:
        return HTTPBadRequest('Missing parameter for docid')

    docid = int(docid)
    tags = find_tags(context)
    profiles = find_profiles(context)
    catalog = find_catalog(context)
    address = catalog.document_map.address_for_docid(docid)
    target = find_model(context, address)
    if tags is not None and profiles is not None:
        users = []
        for userid in tags.getUsers(tags=[tag], items=[docid],
                                    community=context.__name__):
            profile = profiles[userid]
            fullname = profile.firstname + ' ' + profile.lastname
            also = [x for x in tags.getTags(items=[docid], users=[userid],
                                            community=context.__name__)
                         if x != tag]
            users.append({'login': userid,
                          'fullname': fullname,
                          'also': also,
                         })

    else:
        users = ()

    return dict(
        api=api,
        tag=tag,
        url=model_url(target, request),
        title=target.title,
        users=users,
        )
Ejemplo n.º 21
0
def delete_content_view(context, request):
    api = AdminTemplateAPI(context, request, 'Admin UI: Delete Content')
    filtered_content = []

    if 'filter_content' in request.params:
        filtered_content = _get_filtered_content(context, request)
        if not filtered_content:
            api.status_message = 'No content matches your query.'

    if 'delete_content' in request.params:
        paths = request.params.getall('selected_content')
        if paths:
            for path in paths:
                try:
                    content = find_model(context, path)
                    del content.__parent__[content.__name__]
                except KeyError:
                    # Thrown by find_model if we've already deleted an
                    # ancestor of this node.  Can safely ignore becuase child
                    # node has been deleted along with ancestor.
                    pass

            if len(paths) == 1:
                status_message = 'Deleted one content item.'
            else:
                status_message = 'Deleted %d content items.' % len(paths)

            redirect_to = model_url(
                context, request, request.view_name,
                query=dict(status_message=status_message)
            )
            return HTTPFound(location=redirect_to)

    parms = dict(
        api=api,
        menu=_menu_macro(),
        content_select_widget=_content_selection_widget(),
        content_select_grid=_content_selection_grid(),
        filtered_content=filtered_content,
    )
    parms.update(_populate_content_selection_widget(context, request))
    return parms
Ejemplo n.º 22
0
def reindex_catalog(context, path_re=None, commit_interval=200, dry_run=False,
                    output=None, transaction=transaction, indexes=None):

    def commit_or_abort():
        if dry_run:
            output and output('*** aborting ***')
            transaction.abort()
        else:
            output and output('*** committing ***')
            transaction.commit()

    site = find_site(context)
    catalog = site.catalog

    output and output('updating indexes')
    site.update_indexes()
    commit_or_abort()

    if indexes is not None:
        output and output('reindexing only indexes %s' % str(indexes))

    i = 1
    for path, docid in catalog.document_map.address_to_docid.items():
        if path_re is not None and path_re.match(path) is None:
            continue
        output and output('reindexing %s' % path)
        try:
            model = find_model(context, path)
        except KeyError:
            output and output('error: %s not found' % path)
            continue

        if indexes is None:
            catalog.reindex_doc(docid, model)
        else:
            for index in indexes:
                catalog[index].reindex_doc(docid, model)
        if i % commit_interval == 0:
            commit_or_abort()
        i+=1
    commit_or_abort()
Ejemplo n.º 23
0
def delete_content_view(context, request):
    api = AdminTemplateAPI(context, request, 'Admin UI: Delete Content')
    filtered_content = []

    if 'filter_content' in request.params:
        filtered_content = _get_filtered_content(context, request)
        if not filtered_content:
            api.status_message = 'No content matches your query.'

    if 'delete_content' in request.params:
        paths = request.params.getall('selected_content')
        if paths:
            for path in paths:
                content = find_model(context, path)
                del content.__parent__[content.__name__]

            if len(paths) == 1:
                status_message = 'Deleted one content item.'
            else:
                status_message = 'Deleted %d content items.' % len(paths)

            redirect_to = model_url(
                context, request, request.view_name,
                query=dict(status_message=status_message)
            )
            return HTTPFound(location=redirect_to)

    parms = dict(
        api=api,
        menu=_menu_macro(),
        content_select_widget=_content_selection_widget(),
        content_select_grid=_content_selection_grid(),
        filtered_content=filtered_content,
    )
    parms.update(_populate_content_selection_widget(context, request))

    return render_template_to_response(
        'templates/admin/delete_content.pt',
        **parms
    )
Ejemplo n.º 24
0
def main():
    parser = OptionParser(description=__doc__,
                          usage='usage: %prog [options] username password')
    parser.add_option('-C', '--config', dest='config', default=None,
        help="Specify a paster config file. Defaults to $CWD/etc/karl.ini")
    parser.add_option('--dry-run', '-n', dest='dry_run',
        action='store_true', default=False,
        help="Don't actually commit any transaction")

    path = '/'
    options, args = parser.parse_args()
    if args:
        path = args[0]

    config = options.config
    if config is None:
        config = get_default_config()

    root, closer = open_root(config)
    model = find_model(root, path)

    def out(msg):
        sys.stderr.write(msg)
        sys.stderr.write('\n')
        sys.stderr.flush()

    try:
        reset_security_workflow(model, output=out)
    except:
        transaction.abort()
        raise
    else:
        if options.dry_run:
            print 'no transaction committed due to --dry-run'
        else:
            transaction.commit()
Ejemplo n.º 25
0
def list_indexes(context):
    from opencore.tagging.index import TagIndex
    from repoze.catalog.indexes.text import CatalogTextIndex
    from repoze.bfg.traversal import find_model
    
    catalog = find_catalog(context)
    for name, index in catalog.items():
        try:
            if isinstance(index, TagIndex):
                tags = find_site(context).tags
                taglist = list(tags._tagid_to_obj.items())
                print name, (len(taglist), taglist)
            elif isinstance(index, CatalogTextIndex):    
                docids = index.index._docwords
                objs = []
                for docid in docids:
                   path = catalog.document_map.address_for_docid(docid)
                   context = find_model(context, path)
                   objs.append(context)
                print name, (len(objs), objs)   
            else:    
                print name, list_index(index)
        except Exception, e:
            print e    
Ejemplo n.º 26
0
 def context(self):
     if not self._context:
         self._context = find_model(find_site(self.content),
                                    self.eventinfo['context_url'])
     return self._context
Ejemplo n.º 27
0
def _exists(context, path):
    try:
        find_model(context, path)
        return True
    except KeyError:
        return False
Ejemplo n.º 28
0
 def traverse(self, path):
     return find_model(self, unquote(path))
Ejemplo n.º 29
0
 def __call__(self, context, utility_name):
     if utility_name not in self._utilities:
         raise KeyError('`%s` is not a registered utility' % utility_name)
     return find_model(find_root(context), self._utilities[utility_name])
Ejemplo n.º 30
0
def showtag_view(context, request, community=None, user=None, crumb_title=None):
    """Show a page for a particular tag, optionally refined by context."""

    page_title = 'Show Tag'
    api = request.api
    api.page_title = page_title

    # The tag screens (cloud, listing, and this view) each have a
    # "jump box" that allows you to quickly jump to another tag.  All
    # three will point here at /showtag?tag=tag1.  We detect this mode
    # and do a redirect.
    jump_tag = request.params.get('jumptag', False)
    if jump_tag:
        location = model_url(context, request, request.view_name, jump_tag)
        return HTTPFound(location=location)

    # Our strategy is to support tag URLs that are like this:
    #     /showtag/tag1
    # ...instead of:
    #     /tagpage.html?tag=tag1
    # However, our tag data isn't traversable (it is site.tags and not
    # site['tags'].  So we have a view at /showtag that picks apart
    # the next hop in the URL.
    tag = request.subpath
    if not tag:
        # The user didn't provide anything beyond /showtag in the URL
        tag = None
        entries = related = []
    else:
        # Ahh, the good part.  Let's find some tag results and unpack
        # data into what the ZPT needs.
        tag = tag[0]
        page_title = 'Show Tag ' + tag

        catalog = find_catalog(context)
        dm = catalog.document_map
        tags = find_tags(context)
        related = tags.getRelatedTags(tag, user=user, community=community)
        entries = []
        if user:
            users = (user,)
        else:
            users = None
        for docid in tags.getItems(tags=(tag,), users=users,
                                   community=community,
                                   ):
            # XXX Need to wire in batching
            address = dm.address_for_docid(int(docid))
            if address is None:
                raise KeyError(docid)
            resource = find_model(context, address)

            # Skip documents which aren't viewable by authenticated user
            #if not has_permission('view', resource, request):
            #    continue

            # Do a secondary query for each result to find the
            # per-user info
            users = tags.getUsers(tags=(tag,), items=(docid,),
                                  community=community)
            if len(users) == 1:
                tuh = '1 person'
            else:
                tuh = '%s people' % len(users)

            tuhref = model_url(context, request, 'tagusers.html',
                               query={'tag': tag, 'docid': docid})
            entry = {
                'title': resource.title,
                'description': getattr(resource, 'description', ''),
                'href': model_url(resource, request),
                'type': get_content_type_name(resource),
                'tagusers_href': tuhref,
                'tagusers_count': tuh,
                }
            entries.append(entry)

    args = dict(
        api=api,
        tag=tag,
        entries=entries,
        related=related,
    )

    if crumb_title:
        # XXX Would context.title be a bit nicer for displaying to user?
        system_name = get_setting(context, 'system_name', 'KARL')
        args['crumbs'] = '%s / %s / %s' % (
            system_name, crumb_title, context.__name__)

    return dict(**args)
Ejemplo n.º 31
0
def evolve(context):
    root = find_root(context)
    searcher = ICatalogSearch(root)
    categories_and_layers_query = dict(
        interfaces={'query':[ICalendarCategory, ICalendarLayer],
                    'operator':'or'},
        )
    total, docids, resolver = searcher(**categories_and_layers_query)
    changed_categories = {}
    for docid in docids:
        ob = resolver(docid)
        if ob is None:
            # slash in path, likely
            path = root.catalog.document_map.docid_to_address.get(docid)
            if path is not None:
                container_path, ob_name = path.rsplit('/', 1)
                container = find_model(root, container_path)
                name = urllib.unquote(ob_name)
                ob = container.get(name)
            
        if ob is not None:
            ob_name = ob.__name__
            if not (ob_name.startswith('_default_') or is_opaque_id(ob_name)):
                old_path = model_path(ob)
                container = ob.__parent__
                new_name = generate_name(container)
                del container[ob_name]
                ob.__name__ = new_name # XXX required?
                container.add(new_name, ob, send_events=False)
                new_path = model_path(ob)
                index_content(ob, None)
                print 'path fixed: %s -> %s' % (old_path, new_path)
                if ICalendarCategory.providedBy(ob):
                    changed_categories[old_path] = new_path

    if changed_categories:
        # fix layer.paths
        layers_query = dict(interfaces=[ICalendarLayer])
        total, docids, resolver = searcher(**layers_query)
        for docid in docids:
            layer = resolver(docid)
            if layer is not None:
                new_paths = []
                changed = []
                for path in layer.paths:
                    if path in changed_categories:
                        new_paths.append(changed_categories[path])
                        changed.append((path, changed_categories[path]))
                    else:
                        new_paths.append(path)

                if changed:
                    layer.paths = new_paths
                    reindex_content(layer, None)
                    print 'layer fixed: %s, %s' % (
                        model_path(layer), [ '%s -> %s' % x for x in changed ])

        # fix the category of events
        events_query = dict(
            interfaces=[ICalendarEvent],
            )
        total, docids, resolver = searcher(**events_query)
        for docid in docids:
            event = resolver(docid)
            if event is not None:
                category = event.calendar_category
                if category in changed_categories:
                    old_category = event.calendar_category
                    new_category = changed_categories[category]
                    event.calendar_category = new_category
                    reindex_content(event, None)
                    print 'event fixed: %s, %s -> %s' % (
                        model_path(event),
                        old_category,
                        new_category)
Ejemplo n.º 32
0
def move_content(root, src, dst, wf_state):
    try:
        context = find_model(root, src)
    except KeyError:
        print >>sys.stderr, "Source content not found: %s" % src
        sys.exit(-1)

    try:
        dest_folder = find_model(root, dst)
    except KeyError:
        print >>sys.stderr, "Destination folder not found: %s" % dst
        sys.exit(-1)

    src_community = find_community(context)

    catalog = find_catalog(root)
    assert catalog is not None
    users = find_users(root)
    assert users is not None

    if src_community is not None:
        move_header = ('<p><em>This was originally authored '
                       'in the "%s" community.</em></p>' %
                       src_community.title)
    else:
        move_header = ''

    src_folder = context.__parent__
    name = context.__name__

    log.info("Moving %s", model_path(context))
    for obj in postorder(context):
        if hasattr(obj, 'docid'):
            docid = obj.docid
            catalog.document_map.remove_docid(docid)
            catalog.unindex_doc(docid)
    del src_folder[name]

    if (context.creator != 'admin'
            and users.get_by_id(context.creator) is None):
        # give the entry to the system admin
        log.warning(
            "User %s not found; reassigning to admin", context.creator)
        context.creator = 'admin'

    if name in dest_folder:
        name = make_unique_name(dest_folder, context.title)

    dest_folder[name] = context
    for obj in postorder(context):
        if hasattr(obj, 'docid'):
            docid = obj.docid
            catalog.document_map.add(model_path(obj), docid)
            catalog.index_doc(docid, obj)

    if wf_state is not None:
        wf = get_workflow(get_content_type(context), 'security', context)
        wf.transition_to_state(context, None, wf_state)

    if hasattr(context, 'text'):
        context.text = "%s\n%s" % (move_header, context.text)