示例#1
0
class IWebdavSettings(Interface):
    """ ExistDB settings """

    webdav_url = schema.TextLine(
        title=_(u'WebDAV server url'),
        description=_(u'WebDAV base url'),
        default=u'http://localhost:6080/exist/webdav/db',
        required=True)

    webdav_dexterity_subpath = schema.TextLine(
        title=_(u'Dexterity WebDAV subpath'),
        description=_(u'Subpath inside WebDAV for Dexterity content'),
        default=u'',
        required=False)

    webdav_username = schema.TextLine(title=_(u'WebDAV username'),
                                      description=_(u'WebDAV username'),
                                      default=u'admin',
                                      required=True)

    webdav_password = schema.Password(title=_(u'WebDAV password'),
                                      description=_(u'WebDAV password'),
                                      default=u'',
                                      required=True)

    versioning_enabled = schema.Bool(title=_(u'Versioning enabled'),
                                     description=_(u'Versioning enabled'),
                                     default=False)
class IConcept(model.Schema):

    body = RichText(
        title=_(u'Concept content')
    )

    xml_body = XMLText(
        title=_(u'XML Content'),
        required=False
    )
示例#3
0
class IConnector(model.Schema):

    webdav_subpath = schema.TextLine(
        title=_(u'Subdirectory in Exist-DB'),
        description=_(u'Subdirectory in Exist-DB'),
        required=False)

    webdav_username = schema.TextLine(
        title=_(u'(optional) username overriding the system settings'),
        required=False)

    webdav_password = schema.TextLine(
        title=_(u'(optional) password overriding the system settings'),
        required=False)

    api_enabled = schema.Bool(title=_(u'Public web API enabled'),
                              default=False,
                              required=False)

    default_view_anonymous = schema.TextLine(
        title=_(u'Default view (anonymous)'),
        description=_(
            u'Name of a default view for site visitors without edit permission'
        ),
        required=False,
        default=None,
    )

    default_view_authenticated = schema.TextLine(
        title=_(u'Default view (authenticated)'),
        description=_(u'Name of a default view for anonymous site visitors'),
        required=False,
        default=u'@@view',
    )
class DBSettingsEditForm(controlpanel.RegistryEditForm):

    schema = IWebdavSettings
    label = _(u'XML Director core settings')
    description = _(u'')

    def updateFields(self):
        super(DBSettingsEditForm, self).updateFields()

    def updateWidgets(self):
        super(DBSettingsEditForm, self).updateWidgets()
class IXMLDocument(model.Schema):

    xml_content = XMLText(title=_(u'XML Content'), required=False)

    xml_xpath = XMLXPath(
        title=_(u'XML XPath expression'),
        description=_(u'Format: field=<fieldname>,xpath=<xpath expression>'),
        required=False)

    xml_binary = XMLBinary(title=_(u'XML Binary'), required=False)

    xml_image = XMLImage(title=_(u'XML Image'), required=False)
    def __call__(self, *args, **kw):

        user = getSecurityManager().getUser()

        # request/force_default_view can be used to force a redirect to the
        # default anonymous view
        force_default_view = self.request.form.get('force_default_view', 0)
        if force_default_view:
            if user.has_permission(permissions.View, self.context):
                default_view = self.context.default_view_anonymous
                return self.request.response.redirect(
                    '{}/{}'.format(self.context.absolute_url(), default_view))
            else:
                LOG.error(u'Unable to redirect to anonymous default view of ({}, {})'.format(
                    user.getUserName(),
                    self.context.absolute_url(1)))
                raise zExceptions.NotFound()

        if user.has_permission(permissions.ModifyPortalContent, self.context):
            default_view = self.context.default_view_authenticated
            return self.request.response.redirect(
                '{}/{}'.format(self.context.absolute_url(), default_view))
        else:
            default_view = self.context.default_view_anonymous
            if default_view:
                return self.request.response.redirect(
                    '{}/{}'.format(self.context.absolute_url(), default_view))
            else:
                msg = _(u'No default view configured for anonymous visitors')
                self.context.plone_utils.addPortalMessage(msg, 'error')
                raise zExceptions.NotFound()
示例#7
0
    def clear_contents(self):
        """ Remove all sub content """

        handle = self.webdav_handle()
        for name in handle.listdir():
            if handle.isfile(name):
                handle.remove(name)
            else:
                handle.removedir(name, force=True, recursive=False)

        return self.redirect(_(u'eXist-db collection cleared'))
    def clear_contents(self):
        """ Remove all sub content """

        handle = self.webdav_handle()
        for name in handle.listdir():
            if handle.isfile(name):
                handle.remove(name)
            else:
                handle.removedir(name, force=True, recursive=False)

        return self.redirect(_(u'eXist-db collection cleared'))
    def zip_import_ui(self, zip_file=None, subpath=None, clean_directories=None):
        """ Import WebDAV subfolder from an uploaded ZIP file """

        try:
            imported_files = self.zip_import(
                zip_file, subpath, clean_directories)
        except Exception as e:
            msg = u'ZIP import failed'
            LOG.error(msg, exc_info=True)
            return self.redirect(msg, 'error')

        self.logger.log(
            'ZIP file imported ({}, {} files)'.format(zip_file, len(imported_files)), details=imported_files)
        return self.redirect(_(u'Uploaded ZIP archive imported'), subpath=subpath)
class IConnectorSettings(Interface):
    """ Connector settings """

    connector_url = schema.TextLine(
        title=_(u'Connection URL of storage service'),
        description=_(u'WebDAV: http://host:port/path/to/webdav,'
                      'Local filesystem: file://path/to/directory, '
                      'AWS S3: s3://bucketname, SFTP sftp://host/path, '
                      'FTP: ftp://host/path'),
        default=u'http://localhost:6080/exist/webdav/db',
        required=True)

    connector_dexterity_subpath = schema.TextLine(
        title=_(u'Dexterity subpath'),
        description=_(u'Subpath inside storage for Dexterity content'),
        default=u'',
        required=False)

    connector_mode = schema.Choice(
        title=_(u'Connector mode'),
        description=_(u'Connector mode (defaults to Exist-DB)'),
        default=u'existdb',
        required=True,
        vocabulary=CONNECTOR_MODE_VOCAB)

    connector_username = schema.TextLine(
        title=_(u'Username for external storage'),
        description=_(u'Username'),
        default=u'admin',
        required=True)

    connector_password = schema.Password(
        title=_(u'Password for external storage'),
        description=_(u'Password'),
        default=u'',
        required=False)
示例#11
0
    def __call__(self, *args, **kw):

        user = getSecurityManager().getUser()
        if user.has_permission(permissions.ModifyPortalContent, self.context):
            default_view = self.context.default_view_authenticated
            return self.request.response.redirect(
                '{}/{}'.format(self.context.absolute_url(), default_view))
        else:
            default_view = self.context.default_view_anonymous
            if default_view:
                return self.request.response.redirect(
                    '{}/{}'.format(self.context.absolute_url(), default_view))
            else:
                msg = _(u'No default view configured for anonymous visitors')
                self.context.plone_utils.addPortalMessage(msg, 'error')
                raise zExceptions.NotFound()
示例#12
0
    def __call__(self, *args, **kw):

        user = getSecurityManager().getUser()
        if user.has_permission(permissions.ModifyPortalContent, self.context):
            default_view = self.context.default_view_authenticated
            return self.request.response.redirect(
                '{}/{}'.format(self.context.absolute_url(), default_view))
        else:
            default_view = self.context.default_view_anonymous
            if default_view:
                return self.request.response.redirect(
                    '{}/{}'.format(self.context.absolute_url(), default_view))
            else:
                msg = _(u'No default view configured for anonymous visitors')
                self.context.plone_utils.addPortalMessage(msg, 'error')
                raise zExceptions.NotFound()
    def create_collection(self, subpath, name):
        """ Create a new collection """

        if not name:
            raise ValueError(_(u'No "name" given'))

        handle = self.webdav_handle(subpath)
        if handle.exists(name):
            msg = u'Collection already exists'
            self.context.plone_utils.addPortalMessage(msg, 'error')
        else:
            handle.makedir(name)
            msg = u'Collection created'
            self.logger.log('Created {} (subpath: {})'.format(name, subpath))
            self.context.plone_utils.addPortalMessage(msg)
        return self.request.response.redirect(
            '{}/@@view/{}'.format(self.context.absolute_url(), subpath))
    def rename_collection(self, subpath, name, new_name):
        """ Rename a collection """

        if not new_name:
            raise ValueError(_(u'No new "name" given'))

        handle = self.webdav_handle(subpath)
        if handle.exists(name):
            handle.rename(name, new_name)
            msg = u'Collection renamed'
            self.logger.log(
                'Renamed {}  to {} (subpath: {})'.format(name, new_name, subpath))
            self.context.plone_utils.addPortalMessage(msg)
        else:
            msg = u'Collection does not exist'
            self.context.plone_utils.addPortalMessage(msg, 'error')
        return self.request.response.redirect(
            '{}/@@view/{}'.format(self.context.absolute_url(), subpath))
    def rename_collection(self, subpath, name, new_name):
        """ Rename a collection """

        if not new_name:
            raise ValueError(_(u'No new "name" given'))

        handle = self.get_handle(subpath)
        if handle.exists(name):
            handle.rename(name, new_name)
            msg = u'Collection renamed'
            self.logger.log('Renamed {}  to {} (subpath: {})'.format(
                name, new_name, subpath))
            self.context.plone_utils.addPortalMessage(msg)
        else:
            msg = u'Collection does not exist'
            self.context.plone_utils.addPortalMessage(msg, 'error')
        return self.request.response.redirect('{}/@@view/{}'.format(
            self.context.absolute_url(), subpath))
    def create_collection(self, subpath, name):
        """ Create a new collection """

        if not name:
            raise ValueError(_(u'No "name" given'))

        handle = self.get_handle(subpath)
        #        can_unicode = handle.getmeta('unicode_paths')
        if handle.exists(name):
            msg = u'Collection already exists'
            self.context.plone_utils.addPortalMessage(msg, 'error')
        else:
            handle.makedir(name)
            msg = u'Collection created'
            self.logger.log('Created {} (subpath: {})'.format(name, subpath))
            self.context.plone_utils.addPortalMessage(msg)
        return self.request.response.redirect('{}/@@view/{}'.format(
            self.context.absolute_url(), subpath))
    def zip_import_ui(self,
                      zip_file=None,
                      subpath=None,
                      clean_directories=None):
        """ Import WebDAV subfolder from an uploaded ZIP file """

        try:
            imported_files = self.zip_import(zip_file, subpath,
                                             clean_directories)
        except Exception as e:
            msg = u'ZIP import failed'
            LOG.error(msg, exc_info=True)
            return self.redirect(msg, 'error')

        self.logger.log('ZIP file imported ({}, {} files)'.format(
            zip_file, len(imported_files)),
                        details=imported_files)
        return self.redirect(_(u'Uploaded ZIP archive imported'),
                             subpath=subpath)
    def __call__(self, *args, **kw):

        qs = self.request.QUERY_STRING
        user = getSecurityManager().getUser()

        # request/force_default_view can be used to force a redirect to the
        # default anonymous view
        force_default_view = self.request.form.get('force_default_view', 0)
        if force_default_view:
            if user.has_permission(permissions.View, self.context):
                default_view = self.context.default_view_anonymous
                if qs:
                    default_view += '?' + qs
                return self.request.response.redirect('{}/{}'.format(
                    self.context.absolute_url(), default_view))
            else:
                LOG.error(
                    u'Unable to redirect to anonymous default view of ({}, {})'
                    .format(user.getUserName(), self.context.absolute_url(1)))
                raise zExceptions.NotFound()

        if user.has_permission(permissions.ModifyPortalContent, self.context):
            default_view = self.context.default_view_authenticated
            if qs:
                default_view += '?' + qs
            return self.request.response.redirect('{}/{}'.format(
                self.context.absolute_url(), default_view))
        else:
            default_view = self.context.default_view_anonymous
            if default_view:
                if qs:
                    default_view += '?' + qs
                return self.request.response.redirect('{}/{}'.format(
                    self.context.absolute_url(), default_view))
            else:
                msg = _(u'No default view configured for anonymous visitors')
                self.context.plone_utils.addPortalMessage(msg, 'error')
                raise zExceptions.NotFound()
示例#19
0
from xmldirector.plonecore.dx.xml_binary import XMLBinaryDataManager


################################################################
# XML Image Content
################################################################

class IXMLImage(IField):

    """ Marker for XML fields """
    pass


class XMLImage(NamedImageField):
    zope.interface.implements(IXMLImage)


XMLImageFactory = FieldFactory(
    XMLImage, _(u'label_xml_Image_field', default=u'XML (image)'))
XMLImageHandler = plone.supermodel.exportimport.BaseHandler(XMLImage)


class XMLImageDataManager(XMLBinaryDataManager):

    """Attribute field."""
    zope.component.adapts(
        zope.interface.Interface, IXMLImage)

    suffix = '.img'
    return_class = NamedImage
class IConnector(model.Schema):

    connector_url = schema.TextLine(
        title=_(u'(optional) connection URL of storage'),
        description=_(u'WebDAV: http://host:port/path/to/webdav, '
                      'Local filesystem: file://path/to/directory, '
                      'AWS S3: s3://bucketname, ',
                      'SFTP sftp://host/path, '
                      'FTP: ftp://host/path'),
        required=False
    )

    connector_username = schema.TextLine(
        title=_(u'(optional) username overriding the system settings'),
        required=False
    )

    connector_password = schema.Password(
        title=_(u'(optional) password overriding the system settings'),
        required=False
    )

    connector_subpath = schema.TextLine(
        title=_(u'Subdirectory relative to the global connection URL'),
        description=_(
            u'Use this value for configuring a more specific subpath'),
        required=False
    )

    api_enabled = schema.Bool(
        title=_(u'Public web API enabled'),
        default=False,
        required=False
    )

    default_view_anonymous = schema.TextLine(
        title=_(u'Default view (anonymous)'),
        description=_(
            u'Name of a default view for site visitors without edit permission'),
        required=False,
        default=None,
    )

    default_view_authenticated = schema.TextLine(
        title=_(u'Default view (authenticated)'),
        description=_(u'Name of a default view for anonymous site visitors'),
        required=False,
        default=u'@@view',
    )
示例#21
0
################################################################
# XML Binary Content
################################################################


class IXMLBinary(IField):
    """ Marker for XML fields """
    pass


class XMLBinary(NamedFileField):
    zope.interface.implements(IXMLBinary)


XMLBinaryFactory = FieldFactory(
    XMLBinary, _(u'label_xml_binary_field', default=u'XML (binary data)'))
XMLBinaryHandler = plone.supermodel.exportimport.BaseHandler(XMLBinary)


class XMLBinaryDataManager(AttributeDataManager):
    """Attribute field."""
    zope.component.adapts(zope.interface.Interface, IXMLBinary)

    suffix = '.bin'
    return_class = NamedFile

    @property
    def storage_key(self):
        context_id = util.get_storage_key(self.context)
        if not context_id:
            context_id = util.new_storage_key(self.context)
示例#22
0
class IReference(model.Schema):

    body = RichText(title=_(u'Reference content'))

    xml_body = XMLText(title=_(u'XML Content'), required=False)
示例#23
0
class XMLText(Text):
    zope.interface.implements(IXMLText)

    def validate(self, value):
        """ Perform XML validation """

        if value:
            try:
                lxml.etree.fromstring(normalize_xml(value))
            except lxml.etree.XMLSyntaxError as e:
                raise zope.interface.Invalid(u'XML syntax error {}'.format(e))
        return super(XMLText, self).validate(value)


XMLTextFactory = FieldFactory(XMLText,
                              _(u'label_xml_field', default=u'XML (Text)'))
XMLTextHandler = plone.supermodel.exportimport.BaseHandler(XMLText)


class XMLFieldDataManager(z3c.form.datamanager.AttributeField):
    """A dedicated manager for XMLText field."""
    zope.component.adapts(zope.interface.Interface, IXMLText)

    def __init__(self, context, field):
        self.context = context
        self.field = field

    @property
    def storage_key(self):

        context_id = util.get_storage_key(self.context)
示例#24
0
from plone.namedfile import NamedImage

from xmldirector.plonecore.i18n import MessageFactory as _
from xmldirector.plonecore.dx.xml_binary import XMLBinaryDataManager

################################################################
# XML Image Content
################################################################


class IXMLImage(IField):
    """ Marker for XML fields """
    pass


class XMLImage(NamedImageField):
    zope.interface.implements(IXMLImage)


XMLImageFactory = FieldFactory(
    XMLImage, _(u'label_xml_Image_field', default=u'XML (image)'))
XMLImageHandler = plone.supermodel.exportimport.BaseHandler(XMLImage)


class XMLImageDataManager(XMLBinaryDataManager):
    """Attribute field."""
    zope.component.adapts(zope.interface.Interface, IXMLImage)

    suffix = '.img'
    return_class = NamedImage
class XMLXPath(TextLine):
    zope.interface.implements(IXMLXPath)

    def validate(self, value):

        if value:
            mo = parse_field_expression(value)
            try:
                fieldname, xpath_expr = mo
            except TypeError:
                raise zope.interface.Invalid(
                    u'Invalid specification ({})'.format(value))
        return super(XMLXPath, self).validate(value)


XMLXPathFactory = FieldFactory(XMLXPath, _(
    u'label_xml_xpath_field', default=u'XML (extended XPath expression)'))
XMLXPathHandler = plone.supermodel.exportimport.BaseHandler(XMLXPath)

from xmldirector.plonecore.dx.xml_field import XMLFieldDataManager


class IXPathWidget(IWidget):
    pass


class XPathWidget(text.TextWidget):

    """ Widget for XPath expressions."""
    zope.interface.implementsOnly(IXPathWidget)

    def xpath_evaluated(self):
示例#26
0
    def zip_import(self, zip_file=None, subpath=None, clean_directories=[]):
        """ Import WebDAV subfolder from an uploaded ZIP file """

        handle = self.webdav_handle()

        if not zip_file:
            zip_filename = self.request.zipfile.filename
            zip_file = self.request.zipfile
        else:
            zip_filename = zip_file
            zip_file = open(zip_file, 'rb')
            LOG.info('ZIP import ({})'.format(zip_filename))

        # zip_import() can also be used to upload single files
        # into the current webdav folder
        if not zip_filename.endswith('.zip'):
            if subpath:
                target_filename = '{}/{}'.format(subpath, zip_filename)
            else:
                target_filename = zip_filename
            with handle.open(target_filename, 'wb') as fp:
                fp.write(zip_file.read())

            msg = u'File "{}" imported'.format(zip_filename)
            self.context.log(msg)
            return self.redirect(_(msg))

        try:
            with ZipFS(zip_file, 'r') as zip_handle:
                # Cleanup webdav directory first
                for i, name in enumerate(handle.listdir()):
                    if name not in clean_directories:
                        continue
                    if handle.isfile(name):
                        handle.remove(name)
                    else:
                        handle.removedir(name, force=True, recursive=False)
                self.context.log(u'Subdirectory cleared (ZIP import)')

                # setup progressbar
                widgets = ['ZIP import: ', Percentage(), ' ', Bar(
                    marker=RotatingMarker()), ' ', ETA(), ' ']
                files = list(zip_handle.walkfiles())

                try:
                    getConfiguration().testinghome
                    show_progress = False
                except AttributeError:
                    show_progress = True

                if show_progress:
                    pbar = ProgressBar(widgets=widgets, maxval=len(files)).start()

                # import all files from ZIP into WebDAV
                count = 0
                for i, name in enumerate(zip_handle.walkfiles()):
                    if show_progress:
                        pbar.update(i)

                    dirname = '/'.join(name.split('/')[:-1])

                    try:
                        handle.makedir(
                            dirname, recursive=True, allow_recreate=True)
                    except Exception as e:
                        LOG.error(
                            'Failed creating {} failed ({})'.format(dirname, e))

                    LOG.info('ZIP filename({})'.format(name))

                    out_fp = handle.open(name.lstrip('/'), 'wb')
                    zip_fp = zip_handle.open(name, 'rb')
                    out_fp.write(zip_fp.read())
                    out_fp.close()
                    count += 1

                zip_fp.close()
                if show_progress:
                    pbar.finish()

        except fs.zipfs.ZipOpenError as e:
            msg = u'Error opening ZIP file: {}'.format(e)
            return self.redirect(msg, 'error')

        self.context.log(
            u'ZIP file imported ({}, {} files)'.format(zip_filename, count))
        return self.redirect(_(u'Uploaded ZIP archive imported'))

################################################################
# XML Image Content
################################################################


class IXMLImage(IField):

    """ Marker for XML fields """

    pass


class XMLImage(NamedImageField):
    zope.interface.implements(IXMLImage)


XMLImageFactory = FieldFactory(XMLImage, _(u"label_xml_Image_field", default=u"XML (image)"))
XMLImageHandler = plone.supermodel.exportimport.BaseHandler(XMLImage)


class XMLImageDataManager(XMLBinaryDataManager):

    """Attribute field."""

    zope.component.adapts(zope.interface.Interface, IXMLImage)

    suffix = ".img"
    return_class = NamedImage
示例#28
0
class XMLText(Text):
    zope.interface.implements(IXMLText)

    def validate(self, value):
        """ Perform XML validation """

        if value:
            try:
                lxml.etree.fromstring(normalize_xml(value))
            except lxml.etree.XMLSyntaxError as e:
                raise zope.interface.Invalid(u'XML syntax error {}'.format(e))
        return super(XMLText, self).validate(value)


XMLTextFactory = FieldFactory(
    XMLText, _(u'label_xml_field', default=u'XML (Text)'))
XMLTextHandler = plone.supermodel.exportimport.BaseHandler(XMLText)


class XMLFieldDataManager(z3c.form.datamanager.AttributeField):

    """A dedicated manager for XMLText field."""
    zope.component.adapts(
        zope.interface.Interface, IXMLText)

    def __init__(self, context, field):
        self.context = context
        self.field = field

    @property
    def storage_key(self):
示例#29
0
class ITopic(model.Schema):

    body = RichText(title=_(u'Topic content'))

    xml_body = XMLText(title=_(u'XML Content'), required=False)
示例#30
0
################################################################
# XML Binary Content
################################################################

class IXMLBinary(IField):

    """ Marker for XML fields """
    pass


class XMLBinary(NamedFileField):
    zope.interface.implements(IXMLBinary)


XMLBinaryFactory = FieldFactory(
    XMLBinary, _(u'label_xml_binary_field', default=u'XML (binary data)'))
XMLBinaryHandler = plone.supermodel.exportimport.BaseHandler(XMLBinary)


class XMLBinaryDataManager(AttributeDataManager):

    """Attribute field."""
    zope.component.adapts(
        zope.interface.Interface, IXMLBinary)

    suffix = '.bin'
    return_class = NamedFile

    @property
    def storage_key(self):
        context_id = util.get_storage_key(self.context)
    def validate(self, value):

        if value:
            mo = parse_field_expression(value)
            try:
                fieldname, xpath_expr = mo
            except TypeError:
                raise zope.interface.Invalid(
                    u'Invalid specification ({})'.format(value))
        return super(XMLXPath, self).validate(value)


XMLXPathFactory = FieldFactory(
    XMLXPath,
    _(u'label_xml_xpath_field', default=u'XML (extended XPath expression)'))
XMLXPathHandler = plone.supermodel.exportimport.BaseHandler(XMLXPath)

from xmldirector.plonecore.dx.xml_field import XMLFieldDataManager


class IXPathWidget(IWidget):
    pass


class XPathWidget(text.TextWidget):
    """ Widget for XPath expressions."""
    zope.interface.implementsOnly(IXPathWidget)

    def xpath_evaluated(self):
        dm = XMLXPathDataManager(context=self.context, field=self.field)
示例#32
0
    def zip_import(self, zip_file=None, subpath=None, clean_directories=[]):
        """ Import WebDAV subfolder from an uploaded ZIP file """

        handle = self.webdav_handle()

        if not zip_file:
            zip_filename = self.request.zipfile.filename
            zip_file = self.request.zipfile
        else:
            zip_filename = zip_file
            zip_file = open(zip_file, 'rb')
            LOG.info('ZIP import ({})'.format(zip_filename))

        # zip_import() can also be used to upload single files
        # into the current webdav folder
        if not zip_filename.endswith('.zip'):
            if subpath:
                target_filename = '{}/{}'.format(subpath, zip_filename)
            else:
                target_filename = zip_filename
            with handle.open(target_filename, 'wb') as fp:
                fp.write(zip_file.read())

            msg = u'File "{}" imported'.format(zip_filename)
            self.logger.log(msg)
            return self.redirect(_(msg))

        try:
            with ZipFS(zip_file, 'r') as zip_handle:
                # Cleanup webdav directory first
                for i, name in enumerate(handle.listdir()):
                    if name not in clean_directories:
                        continue
                    if handle.isfile(name):
                        handle.remove(name)
                    else:
                        handle.removedir(name, force=True, recursive=False)
                self.logger.log(u'Subdirectory cleared (ZIP import)')

                # setup progressbar
                widgets = ['ZIP import: ', Percentage(), ' ', Bar(
                    marker=RotatingMarker()), ' ', ETA(), ' ']
                files = list(zip_handle.walkfiles())

                try:
                    getConfiguration().testinghome
                    show_progress = False
                except AttributeError:
                    show_progress = True

                if show_progress:
                    pbar = ProgressBar(
                        widgets=widgets, maxval=len(files)).start()

                # import all files from ZIP into WebDAV
                count = 0
                for i, name in enumerate(zip_handle.walkfiles()):
                    if show_progress:
                        pbar.update(i)

                    dirname = '/'.join(name.split('/')[:-1])

                    try:
                        handle.makedir(
                            dirname, recursive=True, allow_recreate=True)
                    except Exception as e:
                        LOG.error(
                            'Failed creating {} failed ({})'.format(dirname, e))

                    LOG.info('ZIP filename({})'.format(name))

                    out_fp = handle.open(name.lstrip('/'), 'wb')
                    zip_fp = zip_handle.open(name, 'rb')
                    out_fp.write(zip_fp.read())
                    out_fp.close()
                    count += 1

                zip_fp.close()
                if show_progress:
                    pbar.finish()

        except fs.zipfs.ZipOpenError as e:
            msg = u'Error opening ZIP file: {}'.format(e)
            return self.redirect(msg, 'error')

        self.logger.log(
            u'ZIP file imported ({}, {} files)'.format(zip_filename, count))
        return self.redirect(_(u'Uploaded ZIP archive imported'))