def __call__(self, published_only=False, filter_uids=[]):

        catalog = getToolByName(self.context, 'portal_catalog')
        # First check if there is a flat for a nested folder structure
        is_folderish = False
        for brain in catalog(
            {'path': '/'.join(self.context.getPhysicalPath())}):
            obj = brain.getObject()
            if obj == self.context:
                continue
            if HAVE_DEXTERITY:
                if (IATFolder.providedBy(obj)
                        or IDexterityContainer.providedBy(obj)):
                    is_folderish = True
                    break
            else:
                if IATFolder.providedBy(obj):
                    is_folderish = True
                    break

        if is_folderish:
            return NestedHTMLView(request=self.request,
                                  context=self.context)(published_only,
                                                        filter_uids)
        else:
            return FlatHTMLView(request=self.request,
                                context=self.context)(published_only,
                                                      filter_uids)
def collector(folder, level=1, published_only=False, html=[], filter_uids=[]):

    utils = getToolByName(folder, 'plone_utils')
    wf_tool = getToolByName(folder, 'portal_workflow')

    for brain in folder.getFolderContents({'sort_on' : 'getObjPositionInParent'}):
        obj = brain.getObject()
        LOG.info('Introspecting %s' % obj.absolute_url(1))
        view = obj.restrictedTraverse('@@asHTML', None)

        if view is not None:
            pt = utils.normalizeString(obj.portal_type)
            review_state = wf_tool.getInfoFor(obj, 'review_state')
            if published_only and review_state not in ['published']:
                continue

            is_folderish = False
            if HAVE_DEXTERITY:
                if (IATFolder.providedBy(obj) or IDexterityContainer.providedBy(obj)) and not IArchiveFolder.providedBy(obj):
                    is_folderish = True
            else:
                if IATFolder.providedBy(obj) and not IArchiveFolder.providedBy(obj):
                    is_folderish = True

            if is_folderish:
                html.append('<div class="mode-nested level-%d document-boundary portal-type-folder review-state-%s" path="%s" id="doc-id-%s" document_id="%s" review_state="%s" level="%d" uid="%s">\n' % 
                            (level, review_state, obj.absolute_url(1), obj.getId(), obj.getId(), review_state, level, obj.UID()))
                if IATFolder.providedBy(obj):
                    folder_title = obj.Title()
                    folder_descr = obj.Description()
                else:
                    folder_title = obj.title # Dexterity
                    folder_descr = obj.description
                html.append('<h%d class="title">%s</h%d>' % (level, folder_title, level))
                html.append('<div class="description">%s</div>' % folder_descr)
                collector(obj, level+1, published_only, html)
                html.append('</div>')

            else:
                html.append('<div class="level-%d document-boundary portal-type-%s review-state-%s" path="%s" id="doc-id-%s" document_id="%s" review_state="%s" level="%d" uid="%s">\n' % 
                            (level, pt, review_state, obj.absolute_url(1), obj.getId(), obj.getId(), review_state, level, obj.UID()))
                html.append('<div class="contentinfo">')
                html.append('<div><a class="editlink" href="%s/edit">Edit</a></div>' % obj.absolute_url())
                try:
                    html.append('<div class="review-state">%s</div>' % wf_tool.getInfoFor(obj, 'review_state'))
                except WorkflowException:
                    pass
                html.append('</div>')
                html.append(view())
                html.append('</div>')
        else :
            LOG.warn('No @@asHTML view found for %s' % obj.absolute_url(1))
Example #3
0
        def collect_objects(folder, level=0, items=[]):
            """ Collect all related subobjects """
            for brain in folder.getFolderContents({'sort_on' : 'getObjPositionInParent'}):
                obj = brain.getObject()

                if IPPContent.providedBy(obj):
                    items.append(dict(obj=obj, level=level))
                else:
                    LOG.warn('IPPContent not provided by %s' % obj.absolute_url(1))

                if HAVE_DEXTERITY:
                    if (IATFolder.providedBy(obj) or IDexterityContainer.providedBy(obj)) and not IArchiveFolder.providedBy(obj):
                        collect_objects(obj, level+1, items)
                else:
                    if IATFolder.providedBy(obj) and not IArchiveFolder.providedBy(obj):
                        collect_objects(obj, level+1, items)
    def get_items(self):
        context = aq_inner(self.context)
        res = ""
        if IATFolder.providedBy(context) or \
                IATBTreeFolder.providedBy(context):
            res = self.context.getFolderContents(
                contentFilter={
                    'sort_on': 'getObjPositionInParent',
                    'portal_type': self.settings.allowed_types,
                    'limit': self.settings.limit
                })
        elif IATTopic.providedBy(context):
            if self.settings.limit and self.settings.limit > 0:
                res = context.queryCatalog(
                    batch=True,
                    b_size=self.settings.limit,
                    portal_type=self.settings.allowed_types,
                )
            else:
                res = context.queryCatalog(
                    portal_type=self.settings.allowed_types,
                    limit=self.settings.limit)
        elif ICollection.providedBy(context):
            query = queryparser.parseFormquery(context, context.getRawQuery())
            query['portal_type'] = self.settings.allowed_types
            query['limit'] = self.settings.limit
            if self.settings.limit and self.settings.limit > 0:
                res = context.queryCatalog(batch=True,
                                           b_size=self.settings.limit)
            else:
                res = context.queryCatalog(query)

        return res
    def get_items(self):
        context = aq_inner(self.context)
        if IATFolder.providedBy(context) or \
                IATBTreeFolder.providedBy(context):
            res = self.context.getFolderContents(
                contentFilter={
                    'sort_on': 'getObjPositionInParent',
                    'portal_type': self.settings.allowed_types,
                    'limit': self.settings.limit
                }
            )
        elif IATTopic.providedBy(context):
            if self.settings.limit and self.settings.limit > 0:
                res = context.queryCatalog(batch=True,
                                           b_size=self.settings.limit,
                                           portal_type=
                                           self.settings.allowed_types,
                                           )
            else:
                res = context.queryCatalog(
                    portal_type=self.settings.allowed_types,
                    limit=self.settings.limit
                )
        elif ICollection.providedBy(context):
            query = queryparser.parseFormquery(
                context, context.getRawQuery())
            query['portal_type'] = self.settings.allowed_types
            query['limit'] = self.settings.limit
            if self.settings.limit and self.settings.limit > 0:
                res = context.queryCatalog(batch=True,
                                           b_size=self.settings.limit)
            else:
                res = context.queryCatalog(query)

        return res
 def available(self):
     context = self.context
     member = getMultiAdapter((context, self.request),
                              name="plone_portal_state").member()
     if IATFolder.providedBy(context) and member.has_permission(
             'monet.calendar.extensions.ManageCalendars', context):
         return IMonetCalendarExtensionsLayer in browserlayerutils.registered_layers(
         )
     return False
Example #7
0
 def getNextPreviousParentValue(self):
     """If the parent node is also an IATFolder and has next/previous
     navigation enabled, then let this folder have it enabled by
     default as well.
     """
     parent = self.getParentNode()
     from Products.ATContentTypes.interface.folder import IATFolder as IATFolder_
     if IATFolder_.providedBy(parent):
         return parent.getNextPreviousEnabled()
     else:
         return False
Example #8
0
        def collect_objects(folder, level=0, items=[]):
            """ Collect all related subobjects """
            for brain in folder.getFolderContents(
                {'sort_on': 'getObjPositionInParent'}):
                obj = brain.getObject()

                if IPPContent.providedBy(obj):
                    items.append(dict(obj=obj, level=level))
                else:
                    LOG.warn('IPPContent not provided by %s' %
                             obj.absolute_url(1))

                if HAVE_DEXTERITY:
                    if (IATFolder.providedBy(obj)
                            or IDexterityContainer.providedBy(obj)
                        ) and not IArchiveFolder.providedBy(obj):
                        collect_objects(obj, level + 1, items)
                else:
                    if IATFolder.providedBy(
                            obj) and not IArchiveFolder.providedBy(obj):
                        collect_objects(obj, level + 1, items)
    def __call__(self, published_only=False, filter_uids=[]):

        catalog = getToolByName(self.context, 'portal_catalog')
        # First check if there is a flat for a nested folder structure
        is_folderish = False
        for brain in catalog({'path' : '/'.join(self.context.getPhysicalPath())}):
            obj = brain.getObject()
            if obj == self.context:
                continue
            if HAVE_DEXTERITY:
                if (IATFolder.providedBy(obj) or IDexterityContainer.providedBy(obj)):
                    is_folderish = True
                    break
            else:
                if IATFolder.providedBy(obj):
                    is_folderish = True
                    break

        if is_folderish:
            return NestedHTMLView(request=self.request, context=self.context)(published_only, filter_uids)
        else:
            return FlatHTMLView(request=self.request, context=self.context)(published_only, filter_uids)
Example #10
0
    def get_events(self):
        context = self.context
        pc = context.portal_catalog

        if IATTopic.providedBy(context):
            query = context.buildQuery()
        elif IATFolder.providedBy(context):
            current_path = "/".join(context.getPhysicalPath())
            query = {"portal_type": "Event", "path": {"query": current_path}}
        query["sort_on"] = "start"
        if self.past_events:
            query["start"] = {"query": DateTime(), "range": "max"}
            query["sort_order"] = "reverse"
        else:
            query["start"] = {"query": DateTime(), "range": "min"}
        return pc.searchResults(query)
    def available(self):
        """Available only if we are on ATFolder and if the folder has a default page view
        (but for this, check the 'display_when_not_default_page' flag)
        """
        context = self.context
        display_when_not_default_page = self.data.display_when_not_default_page
        folder = self._getFolder()

        if not IATFolder.providedBy(folder):
            return False

        if not self.contents():
            return False

        if not display_when_not_default_page:
            if context==folder:
                return False

        return True
    def get_events(self):
        context = self.context
        pc = context.portal_catalog

        if IATTopic.providedBy(context):
            query = context.buildQuery()
        elif IATFolder.providedBy(context):
            current_path = "/".join(context.getPhysicalPath())
            query = {
                "portal_type": "Event",
                "path": { "query": current_path }}
        query["sort_on"] = "start"
        if self.past_events:
            query["start"] = {
                "query": DateTime(), "range" : "max"}
            query["sort_order"] = "reverse"
        else:
            query["start"] = {
                "query": DateTime(), "range" : "min"}
        return pc.searchResults(query)
Example #13
0
    def get_items(self):
        if IATFolder.providedBy(self.context) or \
                IATBTreeFolder.providedBy(self.context):
            res = self.context.getFolderContents(
                contentFilter={
                    'sort_on': 'getObjPositionInParent',
                    'portal_type': self.settings.allowed_types,
                    'limit': self.settings.limit
                }
            )
        elif IATTopic.providedBy(self.context):
            res = aq_inner(self.context).queryCatalog(
                portal_type=self.settings.allowed_types,
                limit=self.settings.limit
            )

        if self.settings.limit == 0:
            return res
        else:
            return res[:self.settings.limit]
    def getEvents(self, start=None, end=None):
        """ searches the catalog for event like objects in the given
        time frame """
        query_func = self.portal_catalog.searchResults
        if IATFolder.providedBy(self.context):
            query_func = self.context.getFolderContents
        elif IATTopic.providedBy(self.context) \
                and self.context.buildQuery() is not None:
            query_func = self.context.queryCatalog
        query = {'object_provides': ICalendarSupport.__identifier__}
        if start:
            query['start'] = {'query': DateTime(int(start)), 'range': 'min'}
        if end:
            query['end'] = {'query': DateTime(int(end)), 'range': 'max'}

        brains = query_func(query)

        jret = []
        for brain in brains:
            jdict = self._buildDict(brain)
            jret.append(jdict)
        return jret
Example #15
0
 def isFolder(self):
     """ Funcio que retorna si es carpeta per tal de mostrar o no el last modified
     """
     if IATFolder.providedBy(self.context) or IPloneSiteRoot.providedBy(
             self.context):
         return True
Example #16
0
def collector(folder, level=1, published_only=False, html=[], filter_uids=[]):

    utils = getToolByName(folder, 'plone_utils')
    wf_tool = getToolByName(folder, 'portal_workflow')

    for brain in folder.getFolderContents(
        {'sort_on': 'getObjPositionInParent'}):
        obj = brain.getObject()
        LOG.info('Introspecting %s' % obj.absolute_url(1))
        view = obj.restrictedTraverse('@@asHTML', None)

        if view is not None:
            pt = utils.normalizeString(obj.portal_type)
            review_state = wf_tool.getInfoFor(obj, 'review_state')
            if published_only and review_state not in ['published']:
                continue

            is_folderish = False
            if HAVE_DEXTERITY:
                if (IATFolder.providedBy(obj)
                        or IDexterityContainer.providedBy(obj)
                    ) and not IArchiveFolder.providedBy(obj):
                    is_folderish = True
            else:
                if IATFolder.providedBy(
                        obj) and not IArchiveFolder.providedBy(obj):
                    is_folderish = True

            if is_folderish:
                html.append(
                    '<div class="mode-nested level-%d document-boundary portal-type-folder review-state-%s" path="%s" id="doc-id-%s" document_id="%s" review_state="%s" level="%d" uid="%s">\n'
                    % (level, review_state, obj.absolute_url(1), obj.getId(),
                       obj.getId(), review_state, level, obj.UID()))
                if IATFolder.providedBy(obj):
                    folder_title = obj.Title()
                    folder_descr = obj.Description()
                else:
                    folder_title = obj.title  # Dexterity
                    folder_descr = obj.description
                html.append('<h%d class="title">%s</h%d>' %
                            (level, folder_title, level))
                html.append('<div class="description">%s</div>' % folder_descr)
                collector(obj, level + 1, published_only, html)
                html.append('</div>')

            else:
                html.append(
                    '<div class="level-%d document-boundary portal-type-%s review-state-%s" path="%s" id="doc-id-%s" document_id="%s" review_state="%s" level="%d" uid="%s">\n'
                    %
                    (level, pt, review_state, obj.absolute_url(1), obj.getId(),
                     obj.getId(), review_state, level, obj.UID()))
                html.append('<div class="contentinfo">')
                html.append(
                    '<div><a class="editlink" href="%s/edit">Edit</a></div>' %
                    obj.absolute_url())
                try:
                    html.append('<div class="review-state">%s</div>' %
                                wf_tool.getInfoFor(obj, 'review_state'))
                except WorkflowException:
                    pass
                html.append('</div>')
                html.append(view())
                html.append('</div>')
        else:
            LOG.warn('No @@asHTML view found for %s' % obj.absolute_url(1))
Example #17
0
 def isFolder(self):
     """ Funcio que retorna si es carpeta per tal de mostrar o no el last modified
     """
     if IATFolder.providedBy(self.context) or IPloneSiteRoot.providedBy(self.context):
         return True
Example #18
0
    def __call2__(self, *args, **kw):
        """ URL parameters:
            'language' -  'de', 'en'....used to override the language of the
                          document
            'converter' - default to on the converters registered with
                          zopyx.convert2 (default: pdf-prince)
            'resource' - the name of a registered resource (directory)
            'template' - the name of a custom template name within the choosen
                         'resource' 
        """

        # Output directory
        tmpdir_prefix = os.path.join(tempfile.gettempdir(),
                                     'produce-and-publish')
        if not os.path.exists(tmpdir_prefix):
            os.makedirs(tmpdir_prefix)
        destdir = tempfile.mkdtemp(dir=tmpdir_prefix,
                                   prefix=self.context.getId() + '-')

        # debug/logging
        params = kw.copy()
        params.update(self.request.form)
        LOG.info('new job (%s, %s) - outdir: %s' % (args, params, destdir))

        # get hold of the language (hyphenation support)
        language = getLanguageForObject(self.context)
        if params.get('language'):
            language = params.get('language')

        # Check for CSS injection
        custom_css = None
        custom_stylesheet = params.get('custom_stylesheet')
        if custom_stylesheet:
            custom_css = str(
                self.context.restrictedTraverse(custom_stylesheet, None))
            if custom_css is None:
                raise ValueError('Could not access custom CSS at %s' %
                                 custom_stylesheet)

        # check for resource parameter
        resource = params.get('resource')
        if resource:
            resources_directory = resources_registry.get(resource)
            if not resources_directory:
                raise ValueError('No resource "%s" configured' % resource)
            if not os.path.exists(resources_directory):
                raise ValueError(
                    'Resource directory for resource "%s" does not exist' %
                    resource)
            self.copyResources(resources_directory, destdir)

            # look up custom template in resources directory
            template_name = params.get('template', 'pdf_template')
            if not template_name.endswith('.pt'):
                template_name += '.pt'
            template_filename = os.path.join(resources_directory,
                                             template_name)
            if not os.path.exists(template_filename):
                raise IOError('No template found (%s)' % template_filename)
            template = ViewPageTemplateFile2(template_filename)

        else:
            template = self.template

        # call the dedicated @@asHTML on the top-level node. For a leaf document
        # this will return either a HTML fragment for a single document or @@asHTML
        # might be defined as an aggregator for a bunch of documents (e.g. if the
        # top-level is a folderish object

        html_view = self.context.restrictedTraverse('@@asHTML', None)
        if not html_view:
            raise RuntimeError(
                'Object at does not provide @@asHTML view (%s, %s)' %
                (self.context.absolute_url(1), self.context.portal_type))
        html_fragment = html_view()

        # arbitrary application data
        data = params.get('data', None)

        # Now render the complete HTML document
        html = template(
            self,
            language=language,
            request=self.request,
            body=html_fragment,
            custom_css=custom_css,
            data=data,
        )

        # and apply transformations
        html = self.transformHtml(html, destdir)

        # hack to replace '&' with '&amp;'
        html = html.replace('& ', '&amp; ')

        # and store it in a dedicated working directory
        dest_filename = os.path.join(destdir, 'index.html')
        fp = codecs.open(dest_filename, 'wb', encoding='utf-8')
        fp.write(html)
        fp.close()

        # split HTML document into parts and store them on the filesystem
        # (making only sense for folderish content)
        if IATFolder.providedBy(self.context) and not 'no-split' in params:
            splitter.split_html(dest_filename, destdir)

        # copy over global styles etc.
        resources_dir = os.path.join(cwd, 'resources')
        self.copyResources(resources_dir, destdir)

        # copy over language dependent hyphenation data
        if language:
            hyphen_file = os.path.join(resources_dir, 'hyphenation',
                                       language + '.hyp')
            if os.path.exists(hyphen_file):
                shutil.copy(hyphen_file, destdir)

            hyphen_css_file = os.path.join(resources_dir, 'languages',
                                           language + '.css')
            if os.path.exists(hyphen_css_file):
                shutil.copy(hyphen_css_file, destdir)

        # now copy over resources (of a derived view)
        self.copyResources(getattr(self, 'local_resources', ''), destdir)
        if ZIP_OUTPUT or 'zip_output' in params:
            archivename = tempfile.mktemp(suffix='.zip')
            fp = zipfile.ZipFile(archivename, "w", zipfile.ZIP_DEFLATED)
            for root, dirs, files in os.walk(destdir):
                #NOTE: ignore empty directories
                for fn in files:
                    absfn = os.path.join(root, fn)
                    zfn = absfn[len(destdir) +
                                len(os.sep):]  #XXX: relative path
                    fp.write(absfn, zfn)
            fp.close()
            LOG.info('ZIP file written to %s' % archivename)

        if 'no_conversion' in params:
            return destdir

        if LOCAL_CONVERSION:
            from zopyx.convert2 import Converter
            c = Converter(dest_filename)
            result = c(params.get('converter', 'pdf-pisa'))
            if result['status'] != 0:
                raise RuntimeError('Error during PDF conversion (%r)' % result)
            pdf_file = result['output_filename']
            LOG.info('Output file: %s' % pdf_file)
            return pdf_file
        else:
            # Produce & Publish server integration
            from zopyx.smartprintng.client.zip_client import Proxy2
            proxy = Proxy2(URL)
            result = proxy.convertZIP2(
                destdir, self.request.get('converter', 'pdf-prince'))
            LOG.info('Output file: %s' % result['output_filename'])
            return result['output_filename']
Example #19
0
    def __call2__(self, *args, **kw):
        """ URL parameters:
            'language' -  'de', 'en'....used to override the language of the
                          document
            'converter' - default to on the converters registered with
                          zopyx.convert2 (default: pdf-prince)
            'resource' - the name of a registered resource (directory)
            'template' - the name of a custom template name within the choosen
                         'resource'
        """

        # Output directory
        tmpdir_prefix = os.path.join(tempfile.gettempdir(),
            'produce-and-publish')
        if not os.path.exists(tmpdir_prefix):
            os.makedirs(tmpdir_prefix)
        destdir = tempfile.mkdtemp(dir=tmpdir_prefix,
            prefix=self.context.getId() + '-')

        # debug/logging
        params = kw.copy()
        params.update(self.request.form)
        LOG.info('new job (%s, %s) - outdir: %s' % (args, params, destdir))

        # get hold of the language (hyphenation support)
        language = getLanguageForObject(self.context)
        if params.get('language'):
            language = params.get('language')

        # Check for CSS injection
        custom_css = None
        custom_stylesheet = params.get('custom_stylesheet')
        if custom_stylesheet:
            custom_css = str(self.context.restrictedTraverse(custom_stylesheet,
                None))
            if custom_css is None:
                raise ValueError(
                    'Could not access custom CSS at %s' % custom_stylesheet)

        # check for resource parameter
        resource = params.get('resource')
        if resource:
            resources_directory = resources_registry.get(resource)
            if not resources_directory:
                raise ValueError('No resource "%s" configured' % resource)
            if not os.path.exists(resources_directory):
                raise ValueError(
            'Resource directory for resource "%s" does not exist' % resource)
            self.copyResources(resources_directory, destdir)

            # look up custom template in resources directory
            template_name = params.get('template', 'pdf_template')
            if not template_name.endswith('.pt'):
                template_name += '.pt'
            template_filename = os.path.join(resources_directory,
                template_name)
            if not os.path.exists(template_filename):
                raise IOError('No template found (%s)' % template_filename)
            template = ViewPageTemplateFile2(template_filename)

        else:
            template = self.template

        html_view = self.context.restrictedTraverse('@@asHTML', None)
        if not html_view:
            raise RuntimeError(
                'Object at does not provide @@asHTML view (%s, %s)' %
                (self.context.absolute_url(1), self.context.portal_type))
        html_fragment = html_view()

        # arbitrary application data
        data = params.get('data', None)

        # Now render the complete HTML document
        html = template(self,
                        language=language,
                        request=self.request,
                        body=html_fragment,
                        custom_css=custom_css,
                        data=data,
                        )

        # and apply transformations
        html = self.transformHtml(html, destdir)

        # hack to replace '&' with '&amp;'
        html = html.replace('& ', '&amp; ')

        # and store it in a dedicated working directory
        dest_filename = os.path.join(destdir, 'index.html')
        fp = codecs.open(dest_filename, 'wb', encoding='utf-8')
        fp.write(html)
        fp.close()
        # split HTML document into parts and store them on the filesystem
        # (making only sense for folderish content)
        if IATFolder.providedBy(self.context) and not 'no-split' in params:
            splitter.split_html(dest_filename, destdir)

        # copy over global styles etc.
        resources_dir = os.path.join(cwd, 'resources')
        self.copyResources(resources_dir, destdir)

        # copy over language dependent hyphenation data
        if language:
            hyphen_file = os.path.join(resources_dir,
                'hyphenation', language + '.hyp')
            if os.path.exists(hyphen_file):
                shutil.copy(hyphen_file, destdir)

            hyphen_css_file = os.path.join(resources_dir, 'languages',
                language + '.css')
            if os.path.exists(hyphen_css_file):
                shutil.copy(hyphen_css_file, destdir)

        # now copy over resources (of a derived view)
        self.copyResources(getattr(self, 'local_resources', ''), destdir)
        if ZIP_OUTPUT or 'zip_output' in params:
            archivename = tempfile.mktemp(suffix='.zip')
            fp = zipfile.ZipFile(archivename, "w", zipfile.ZIP_DEFLATED)
            for root, dirs, files in os.walk(destdir):
                #NOTE: ignore empty directories
                for fn in files:
                    absfn = os.path.join(root, fn)
                    zfn = absfn[len(destdir) + len(os.sep):]
                    fp.write(absfn, zfn)
            fp.close()
            LOG.info('ZIP file written to %s' % archivename)

        if 'no_conversion' in params:
            return destdir
        if LOCAL_CONVERSION:
            from zopyx.convert2 import Converter
            c = Converter(dest_filename)
            result = c(params.get('converter', 'pdf-pisa'))
            if result['status'] != 0:
                raise RuntimeError('Error during PDF conversion (%r)' % result)
            pdf_file = result['output_filename']
            LOG.info('Output file: %s' % pdf_file)
            return pdf_file
        else:
            # Produce & Publish server integration
            from zopyx.smartprintng.client.zip_client import Proxy2
            proxy = Proxy2(URL)
            result = proxy.convertZIP2(destdir, self.request.get('converter',
                'pdf-prince'))
            LOG.info('Output file: %s' % result['output_filename'])
            return result['output_filename']