def new_folder(self, name, subpath=None): """ Create a new collection ``name`` inside the folder ``subpath `` """ if self.is_readonly: raise zExceptions.Forbidden(_('Connector is readonly')) if not name: raise ValueError(_('No name given')) name = safe_unicode(name) subpath = safe_unicode(subpath or self.subpath) handle = self.context.get_handle(subpath) if handle.exists(name): msg = _('{}/{} already exists found').format(subpath, name) self.messages.add(msg, 'error') return self.request.response.redirect(self.context.absolute_url() + '/view/' + subpath) try: handle.makedir(name) except Exception as e: msg = _('{}/{} could not be created ({})').format(subpath, name, str(e)) self.messages.add(msg, 'error') return self.request.response.redirect(self.context.absolute_url() + '/' + subpath) msg = _('Created {}/{}').format(subpath, name) self.messages.add(msg, 'info') self.request.response.redirect(self.context.absolute_url() + '/view/' + subpath + '/' + name)
def remove(self, resource_name): """ Remove a resource by path/name """ if self.is_readonly: raise zExceptions.Forbidden(_('Connector is readonly')) subpath = safe_unicode(self.request.get('subpath', self.subpath)) handle = self.context.get_handle() if not handle.exists(resource_name): msg = 'Not found {}'.format(resource_name) raise zExceptions.NotFound(msg) if handle.isdir(resource_name): try: handle.removetree(resource_name) except Exception as e: msg = resource_name + _(' could not be deleted') + ' ({})'.format(e) self.request.response.setStatus(500) return msg elif handle.isfile(resource_name): try: handle.remove(resource_name) except Exception as e: msg = _('{} could not be deleted ({})').format(resource_name, e) self.request.response.setStatus(500) return msg else: msg = _('Unhandled file type for {}').format(resource_name) raise RuntimeError(msg) msg = _('Deleted {}').format(resource_name) self.request.response.setStatus(200)
def rename(self, resource_name, new_name): """ Rename a resource """ if self.is_readonly: raise zExceptions.Forbidden(_('Connector is readonly')) resource_name = safe_unicode(resource_name) new_name = safe_unicode(new_name) dirname = fs.path.dirname(resource_name) new_resource_name = fs.path.join(dirname, new_name) handle = self.context.get_handle() if handle.exists(new_resource_name): raise ValueError(_('Target {} exists').format(resource_name)) if handle.isfile(resource_name): try: handle.move(resource_name, new_resource_name) except Exception as e: msg = resource_name + _(' could not be moved') + ' ({})'.format(e) self.request.response.setStatus(500) return msg else: try: fs.move.move_dir(handle, resource_name, handle, new_resource_name) except Exception as e: msg = resource_name + _(' could not be moved') + ' ({})'.format(e) self.request.response.setStatus(500) return msg msg = _('Renamed {} to {}').format(resource_name, new_name) self.request.response.setStatus(200)
class DBSettingsEditForm(controlpanel.RegistryEditForm): schema = IConnectorSettings label = _(u'XML Director Connector settings') description = _(u'') def updateFields(self): super(DBSettingsEditForm, self).updateFields() def updateWidgets(self): super(DBSettingsEditForm, self).updateWidgets()
class IConnector(model.Schema): connector_url = schema.TextLine(title=_(u'(optional) connection URL of storage'), description=_( u'WebDAV: webdav://host:port/path/to/webdav, ' 'local filesystem: file://path/to/directory, ' 'AWS S3: s3://bucketname, ', 'SFTP sftp://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) connector_readonly = schema.Bool(title=_(u'Readonly access'), default=False, required=False) form.widget("connector_reference", SelectWidget) connector_reference = schema.Choice( title=_("Reference to other connector "), required=False, source=get_connector_references, default=None, )
def zip_import_ui(self, zip_file=None, subpath=None, clean_directories=None): """ Import WebDAV subfolder from an uploaded ZIP file """ if self.is_readonly: raise zExceptions.Forbidden(_('Connector is readonly')) 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 zip_import(self, zip_file=None): """ Import subfolder from an uploaded ZIP file """ if self.is_readonly: raise zExceptions.Forbidden(_('Connector is readonly')) subpath = self.request.get('subpath') or self.subpath handle = self.context.get_handle(subpath) if not zip_file: zip_filename = self.request.zipfile.filename temp_fn = tempfile.mktemp(suffix='.zip') with open(temp_fn, 'wb') as fp: self.request.zipfile.seek(0) fp.write(self.request.zipfile.read()) zip_file = temp_fn else: zip_filename = zip_file if not zip_filename: raise ValueError(u'No filename detected. Did you really upload a ZIP file?') if not zip_filename.endswith('.zip'): raise ValueError(u'Uploaded file did not end with .zip. Did you really upload a ZIP file?') try: with fs.zipfs.ZipFS(zip_file, encoding='utf-8') as zip_handle: # import all files from ZIP into WebDAV count = 0 dirs_created = set() for i, name in enumerate(zip_handle.walk.files()): target_filename = unicodedata.normalize('NFC', name).lstrip('/') if self.subpath: target_filename = u'{}/{}'.format(self.subpath, target_filename) target_dirname = '/'.join(target_filename.split('/')[:-1]) if target_dirname not in dirs_created: try: handle.makedirs(target_dirname, recreate=True) dirs_created.add(target_dirname) except Exception as e: LOG.error('Failed creating {} failed ({})'.format(target_dirname, e)) LOG.info(u'ZIP filename({})'.format(name)) out_fp = handle.open(target_filename, 'wb') zip_fp = zip_handle.open(name, 'rb') out_fp.write(zip_fp.read()) out_fp.close() count += 1 except Exception as e: msg = 'Error opening ZIP file: {}'.format(e) raise self.request.response.redirect(self.context.absolute_url() + '/view/' + subpath)
def upload_file(self): """ AJAX callback for Uploadify """ if self.is_readonly: raise zExceptions.Forbidden(_('Connector is readonly')) subpath = safe_unicode(self.request.get('subpath', self.subpath)) filename = safe_unicode(os.path.basename(self.request.file.filename)) basename, ext = os.path.splitext(filename) handle = self.context.get_handle(subpath) with handle.open(filename, 'wb') as fp: self.request.file.seek(0) data = self.request.file.read() fp.write(data) self.request.response.setStatus(200)
class IConnectorSettings(Interface): """ Connector settings """ connector_url = schema.TextLine( title=_(u'Connection URL of storage'), description=_(u'WebDAV: webdav://host:port/path/to/webdav, ' 'local filesystem: file://path/to/directory, ' 'AWS S3: s3://bucketname, SFTP sftp://host/path'), default=u'', required=True) connector_username = schema.TextLine( title=_(u'Username for external storage'), description=_(u'Username'), default=u'admin', required=False) connector_password = schema.Password(title=_(u'Password external storage'), description=_(u'Password'), default=u'', required=False)