def add(self, path, newfile, replacepath=None): """Add the uploaded file to the specified path. Unlike the other methods, this method must return its JSON response wrapped in an HTML <textarea>, so the MIME type of the response is text/html instead of text/plain. The upload form in the File Manager passes the current path as a POST param along with the uploaded file. The response includes the path as well as the name used to store the file. The uploaded file's name should be safe to use as a path component in a URL, so URL-encoded at a minimum. """ if six.PY2: path = safe_encode(path, 'utf-8') if six.PY2 and replacepath is not None: replacepath = safe_encode(replacepath, 'utf-8') parentPath = self.normalizePath(path) error = '' code = 0 name = newfile.filename if six.PY2 and isinstance(name, six.text_type): name = safe_encode(name, 'utf-8') if replacepath: newPath = replacepath parentPath = '/'.join(replacepath.split('/')[:-1]) else: newPath = '{0}/{1}'.format(parentPath, name,) try: parent = self.getObject(parentPath) except KeyError: error = translate(_(u'filemanager_invalid_parent', default=u'Parent folder not found.'), context=self.request) code = 1 else: if name in parent and not replacepath: error = translate(_(u'filemanager_error_file_exists', default=u'File already exists.'), context=self.request) code = 1 else: try: self.resourceDirectory.writeFile(newPath, newfile) except ValueError: error = translate(_(u'filemanager_error_file_invalid', default=u'Could not read file.'), context=self.request) code = 1 return { 'parent': self.normalizeReturnPath(parentPath), 'path': self.normalizeReturnPath(path), 'name': name, 'error': error, 'code': code, }
def test_safe_encode(self): """safe_encode should always encode unicode to the specified encoding. """ from Products.CMFPlone.utils import safe_encode self.assertEqual(safe_encode(u'späm'), b'sp\xc3\xa4m') self.assertEqual(safe_encode(u'späm', 'utf-8'), b'sp\xc3\xa4m') self.assertEqual(safe_encode(u'späm', encoding='latin-1'), b'sp\xe4m')
def test_safe_encode(self): """safe_encode should always encode unicode to the specified encoding. """ from Products.CMFPlone.utils import safe_encode self.assertEqual(safe_encode(u'späm'), 'sp\xc3\xa4m') self.assertEqual(safe_encode(u'späm', 'utf-8'), 'sp\xc3\xa4m') self.assertEqual(safe_encode(u'späm', encoding='latin-1'), 'sp\xe4m') self.assertEqual(('spam'), 'spam')
def saveFile(self, path, value): processInputs(self.request) path = self.request.form.get('path', path) value = self.request.form.get('value', value) if six.PY2: path = safe_encode(path, 'utf-8') value = safe_encode(value, 'utf-8') path = path.lstrip('/') value = value.replace('\r\n', '\n') self.context.writeFile(path, value) return ' ' # Zope no likey empty responses
def addFolder(self, path, name): """Create a new directory on the server within the given path. """ if six.PY2: path = safe_encode(path, 'utf-8') name = safe_encode(name, 'utf-8') code = 0 error = '' parentPath = self.normalizePath(path) parent = None try: parent = self.getObject(parentPath) except KeyError: error = translate(_(u'filemanager_invalid_parent', default=u'Parent folder not found.'), context=self.request) code = 1 else: if not validateFilename(name): error = translate(_(u'filemanager_invalid_foldername', default=u'Invalid folder name.'), context=self.request) code = 1 elif name in parent: error = translate(_(u'filemanager_error_folder_exists', default=u'Folder already exists.'), context=self.request) code = 1 else: try: parent.makeDirectory(name) except UnicodeDecodeError: error = translate( _( u'filemanager_invalid_foldername', default=u'Invalid folder name.' ), context=self.request ) code = 1 self.request.response.setHeader('Content-Type', 'application/json') return json.dumps({ 'parent': self.normalizeReturnPath(parentPath), 'name': name, 'error': error, 'code': code, })
def test_subscribers_upload_create_subscribers(self): template = """salutation,name_prefix,firstname,lastname,email,organization Ms,PhD,Jane,Doe,[email protected],Doe Cörp Mr,PhD,John,Doe,[email protected],Doe Cörp """ filename = os.path.join(os.path.dirname(__file__), "easynewsletter-subscribers.csv") if six.PY2: with open(filename, "wb") as f: f.write(safe_encode(template)) else: with open(filename, "w", newline="") as f: f.write(safe_unicode(template)) if six.PY2: file = open(filename) else: file = open(filename, "rb") self.portal.REQUEST.form.update({ 'form.button.Import': 'submit', 'csv_upload': file, }) view = getMultiAdapter((self.newsletter, self.portal.REQUEST), name="subscribers-upload") self.assertTrue(view.__name__ == "subscribers-upload") view.create_subscribers() file.close()
def writeDataFile(self, filename, text, content_type, subdir=None): if filename not in self.filenames: return if filename == 'types.xml': # Remove all the types except our targets. # Strategy: suck into ElementTree element, remove nodes, # convert back to text, prettify. root = etree.fromstring(text) todelete = [] for element in root.getchildren(): name = element.attrib['name'] if name != 'title' and name not in self.typelist: todelete.append(element) for element in todelete: root.remove(element) # Add a marker for ZopeSkel additions root.append(etree.Comment(' -*- extra stuff goes here -*- ')) # minor prettifying root_str = safe_unicode(etree.tostring(root)) text = '<?xml version="1.0"?>\n{0}'.format(root_str) text = text.replace('<!--', ' <!--') text = text.replace('-->', '-->\n') self._archive.writestr(filename, safe_encode(text))
def handleSubmit(self, action): unsorted_data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return unsorted_data = self.updateServerSideData(unsorted_data) errors = self.processActions(unsorted_data) if errors: return self.setErrorsMessage(errors) data = OrderedDict( [x for x in getFieldsInOrder(self.schema) if x[0] in unsorted_data] ) data.update(unsorted_data) thanksPageOverride = self.context.thanksPageOverride if not thanksPageOverride: # we come back to the form itself. # the thanks page is handled in the __call__ method return thanksPageOverrideAction = self.context.thanksPageOverrideAction thanksPage = get_expression(self.context, thanksPageOverride) if six.PY2 and isinstance(thanksPage, six.text_type): thanksPage = thanksPage.encode("utf-8") if thanksPageOverrideAction == "redirect_to": self.request.response.redirect(thanksPage) return if thanksPageOverrideAction == "traverse_to": thanksPage = self.context.restrictedTraverse(thanksPage) thanksPage = mapply(thanksPage, self.request.args, self.request) self.request.response.write(safe_encode(thanksPage))
def getFolder(self, path, getSizes=False): """Returns a dict of file and folder objects representing the contents of the given directory (indicated by a "path" parameter). The values are dicts as returned by getInfo(). A boolean parameter "getsizes" indicates whether image dimensions should be returned for each item. Folders should always be returned before files. Optionally a "type" parameter can be specified to restrict returned files (depending on the connector). If a "type" parameter is given for the HTML document, the same parameter value is reused and passed to getFolder(). This can be used for example to only show image files in a file system tree. """ if six.PY2: path = safe_encode(path, 'utf-8') folders = [] files = [] path = self.normalizePath(path) folder = self.getObject(path) for name in folder.listDirectory(): if IResourceDirectory.providedBy(folder[name]): folders.append(self.getInfo( path='{0}/{1}/'.format(path, name), getSize=getSizes)) else: files.append(self.getInfo( path='{0}/{1}'.format(path, name), getSize=getSizes)) return folders + files
def delete(self, path): """Delete the item at the given path. """ if six.PY2: path = safe_encode(path, 'utf-8') npath = self.normalizePath(path) parentPath = '/'.join(npath.split('/')[:-1]) name = npath.split('/')[-1] code = 0 error = '' try: parent = self.getObject(parentPath) except KeyError: error = translate(_(u'filemanager_invalid_parent', default=u'Parent folder not found.'), context=self.request) code = 1 else: try: del parent[name] except KeyError: error = translate(_(u'filemanager_error_file_not_found', default=u'File not found.'), context=self.request) code = 1 self.request.response.setHeader('Content-Type', 'application/json') return json.dumps({ 'path': self.normalizeReturnPath(path), 'error': error, 'code': code, })
def getFile(self, path): if six.PY2: path = safe_encode(path, 'utf-8') path = self.normalizePath(path) ext = self.getExtension(path=path) result = {'ext': ext} self.request.response.setHeader('Content-Type', 'application/json') if ext in self.imageExtensions: obj = self.getObject(path) info = self.getInfo(obj) info['preview'] = path result['info'] = self.previewTemplate(info=info) return json.dumps(result) else: data = self.context.openFile(path) try: data = data.read() if six.PY2 and isinstance(data, six.text_type): result['contents'] = data.encode('utf8') else: result['contents'] = safe_unicode(data) try: return json.dumps(result) except UnicodeDecodeError: # The file we're trying to get isn't unicode encodable # so we just return the file information, not the content del result['contents'] obj = self.getObject(path) info = self.getInfo(obj) result['info'] = self.previewTemplate(info=info) return json.dumps(result) except AttributeError: return None
def safe_nativestring(value, encoding='utf-8'): """Convert a value to str in py2 and to text in py3 """ if six.PY2 and isinstance(value, six.text_type): value = safe_encode(value, encoding) if not six.PY2 and isinstance(value, six.binary_type): value = safe_unicode(value, encoding) return value
def renameFile(self, path, newName): """Rename the item at the given path to the new name """ if six.PY2: path = safe_encode(path, 'utf-8') newName = safe_encode(newName, 'utf-8') npath = self.normalizePath(path) oldPath = newPath = '/'.join(npath.split('/')[:-1]) oldName = npath.split('/')[-1] code = 0 error = '' try: parent = self.getObject(oldPath) except KeyError: error = translate(_(u'filemanager_invalid_parent', default=u'Parent folder not found.'), context=self.request) code = 1 else: if newName != oldName: if newName in parent: error = translate( _( u'filemanager_error_file_exists', default=u'File already exists.' ), context=self.request) code = 1 else: parent.rename(oldName, newName) self.request.response.setHeader('Content-Type', 'application/json') return json.dumps({ 'oldParent': self.normalizeReturnPath(oldPath), 'oldName': oldName, 'newParent': self.normalizeReturnPath(newPath), 'newName': newName, 'error': error, 'code': code, })
def __call__(self): context = aq_inner(self.context) # Create CSV file filename = tempfile.mktemp() if six.PY2: file = open(filename, "wb") csvWriter = UnicodeWriter(file, { "delimiter": ",", "quotechar": '"', "quoting": csv.QUOTE_MINIMAL }) else: file = open(filename, "w", newline="") csvWriter = csv.writer( file, dialect="excel", delimiter=",", quotechar='"', quoting=csv.QUOTE_MINIMAL, ) csvWriter.writerow([x for x in CSV_HEADER]) for subscriber in api.content.find(portal_type="Newsletter Subscriber", context=self.context, sort_on="email"): obj = subscriber.getObject() csvWriter.writerow([ obj.salutation, obj.name_prefix, obj.firstname, obj.lastname, # obj.nl_language, obj.email, obj.organization, ]) file.close() with open(filename, "r") as f: data = f.read() data = safe_encode(data) # Create response response = context.REQUEST.response response.addHeader( "Content-Disposition", "attachment; filename=easynewsletter-subscribers.csv") response.addHeader("Content-Type", "text/csv") response.addHeader("Content-Length", "%d" % len(data)) response.addHeader("Pragma", "no-cache") response.addHeader( "Cache-Control", "must-revalidate, post-check=0, pre-check=0, public") response.addHeader("Expires", "0") # Return CSV data return data
def addFile(self, path, name): """Add a new empty file in the given directory """ if six.PY2: path = safe_encode(path, 'utf-8') name = safe_encode(name, 'utf-8') error = '' code = 0 parentPath = self.normalizePath(path) newPath = '{0}/{1}'.format(parentPath, name,) try: parent = self.getObject(parentPath) except KeyError: error = translate(_(u'filemanager_invalid_parent', default=u'Parent folder not found.'), context=self.request) code = 1 else: if not validateFilename(name): error = translate(_(u'filemanager_invalid_filename', default=u'Invalid file name.'), context=self.request) code = 1 elif name in parent: error = translate(_(u'filemanager_error_file_exists', default=u'File already exists.'), context=self.request) code = 1 else: self.resourceDirectory.writeFile(newPath, b'') self.request.response.setHeader('Content-Type', 'application/json') return json.dumps({ 'parent': self.normalizeReturnPath(parentPath), 'name': name, 'error': error, 'code': code, 'path': path })
def writerow(self, row): # row = [s or '' for s in row] row = [safe_encode(s) or b"" for s in row] self.writer.writerow(row) data = self.queue.getvalue() data = safe_unicode(data) data = self.encoder.encode(safe_unicode(data)) # write to the target stream self.stream.write(data) # empty queue self.queue.truncate(0)
def saveFile(self, path, value): path = path.lstrip('/') if six.PY2: path = safe_encode(path, 'utf-8') value = value.strip() if six.PY2: value = safe_encode(value, 'utf-8') value = value.replace('\r\n', '\n') if path in self.context: if IResourceDirectory.providedBy(self.context[path]): return json.dumps({'error': 'invalid path'}) if 'relativeUrls' in self.request.form: reg = re.compile('url\(([^)]+)\)') urls = reg.findall(value) # Trim off the @@plone.resourceeditor bit to just give us the # theme url limit = self.request.URL.find('@@plone.resourceeditor') location = self.request.URL[0:limit] base = urlparse(location) for url in urls: asset = urlparse(url.strip("'").strip('"')) if base.netloc != asset.netloc: continue base_dir = '.' + posixpath.dirname(base.path) target = '.' + asset.path out = posixpath.relpath(target, start=base_dir) value = value.replace(url.strip('"').strip("'"), out) self.request.response.setHeader('Content-Type', 'application/json') if isinstance(self.context, FilesystemResourceDirectory): # we cannot save in an FS directory, but we return the file content # (useful when we compile less from the theming editor) return json.dumps({'success': 'tmp', 'value': value}) else: self.context.writeFile(path, value) return json.dumps({'success': 'save'})
def exportRegistry(context): logger = context.getLogger('plone.app.registry') registry = queryUtility(IRegistry) if registry is None: logger.info("Cannot find registry") return exporter = RegistryExporter(registry, context) body = exporter.exportDocument() if body is not None: context.writeDataFile('registry.xml', safe_encode(body), 'text/xml')
def fix_workspace_members(context): """ This makes sense only on Python2 because on Python3 the index keys will already be str instances in any case """ if not six.PY2: return pc = api.portal.get_tool("portal_catalog") index = pc._catalog.indexes.get("workspace_members") if not index: return keys_to_fix = (key for key in index._index if isinstance(key, six.text_type)) for key in keys_to_fix: index._index[safe_encode(key)] = index._index.pop(key)
def getFile(self, path): self.setup() if six.PY2: path = safe_encode(path, 'utf-8') path = self.normalizePath(path) file = self.context.context.unrestrictedTraverse(path) ext = self.getExtension(path, file) result = {'ext': ext} if ext not in self.imageExtensions: result['contents'] = str(file.data) else: info = self.getInfo(path) result['info'] = self.previewTemplate(info=info) self.request.response.setHeader('Content-Type', 'application/json') return json.dumps(result)
def download(self, path): """Serve the requested file to the user """ if six.PY2: path = safe_encode(path, 'utf-8') npath = self.normalizePath(path) parentPath = '/'.join(npath.split('/')[:-1]) name = npath.split('/')[-1] parent = self.getObject(parentPath) self.request.response.setHeader('Content-Type', 'application/octet-stream') self.request.response.setHeader( 'Content-Disposition', 'attachment; filename="{0}"'.format(name) ) # TODO: Use streams here if we can return parent.readFile(name)
def __call__( self, fieldname=None, direction="thumbnail", height=None, width=None, scale=None, **parameters ): """Factory for image scales`. """ orig_value = getattr(self.context, fieldname, None) if orig_value is None: return if height is None and width is None: dummy, format_ = orig_value.contentType.split("/", 1) return None, format_, (orig_value._width, orig_value._height) elif not parameters and height and width \ and height == getattr(orig_value, "_height", None) \ and width == getattr(orig_value, "_width", None): dummy, format_ = orig_value.contentType.split("/", 1) return orig_value, format_, (orig_value._width, orig_value._height) orig_data = None try: orig_data = orig_value.open() except AttributeError: orig_data = getattr(aq_base(orig_value), "data", orig_value) if not orig_data: return # Handle cases where large image data is stored in FileChunks instead # of plain string if isinstance(orig_data, tuple(FILECHUNK_CLASSES)): # Convert data to 8-bit string # (FileChunk does not provide read() access) orig_data = str(orig_data) # If quality wasn't in the parameters, try the site's default scaling # quality if it exists. if "quality" not in parameters: quality = self.get_quality() if quality: parameters["quality"] = quality if not getattr(orig_value, "contentType", "") == "image/svg+xml": try: result = self.create_scale( orig_data, direction=direction, height=height, width=width, **parameters ) except (ConflictError, KeyboardInterrupt): raise except Exception: logger.exception( 'Could not scale "{0!r}" of {1!r}'.format( orig_value, self.context.absolute_url(), ), ) return if result is None: return else: if isinstance(orig_data, (six.text_type)): orig_data = safe_encode(orig_data) if isinstance(orig_data, (bytes)): orig_data = BytesIO(orig_data) result = orig_data.read(), "svg+xml", (width, height) data, format_, dimensions = result mimetype = "image/{0}".format(format_.lower()) value = orig_value.__class__( data, contentType=mimetype, filename=orig_value.filename, ) value.fieldname = fieldname # make sure the file is closed to avoid error: # ZODB-5.5.1-py3.7.egg/ZODB/blob.py:339: ResourceWarning: # unclosed file <_io.FileIO ... mode='rb' closefd=True> if isinstance(orig_data, BlobFile): orig_data.close() return value, format_, dimensions
def scrub_html(self, orig): # append html tag to create a dummy parent for the tree html_parser = html.HTMLParser(encoding="utf-8") orig = safe_encode(orig) tag = b"<html" if tag in orig.lower(): # full html tree = html.fromstring(orig, parser=html_parser) strip_outer = bodyfinder else: # partial html (i.e. coming from WYSIWYG editor) tree = html.fragment_fromstring(orig, create_parent=True, parser=html_parser) def strip_outer(s): return s[5:-6] for elem in tree.iter(etree.Element): if elem is not None: for attrib, value in elem.attrib.items(): if hasScript(value): del elem.attrib[attrib] registry = getUtility(IRegistry) self.settings = registry.forInterface(IFilterSchema, prefix="plone") valid_tags = self.settings.valid_tags nasty_tags = [t for t in self.settings.nasty_tags if t not in valid_tags] if six.PY2: safe_attrs = [attr.decode() for attr in html.defs.safe_attrs] else: safe_attrs = [i for i in html.defs.safe_attrs] safe_attrs.extend(self.settings.custom_attributes) remove_script = "script" in nasty_tags and 1 or 0 cleaner = Cleaner( kill_tags=nasty_tags, remove_tags=[], allow_tags=valid_tags, page_structure=False, safe_attrs_only=True, safe_attrs=safe_attrs, embedded=False, remove_unknown_tags=False, meta=False, javascript=remove_script, scripts=remove_script, forms=False, style=False, ) try: cleaner(tree) except AssertionError: # some VERY invalid HTML return "" # remove all except body or outer div # changes in # https://github.com/plone/Products.PortalTransforms/pull/43 if six.PY2: result = etree.tostring(tree, encoding="utf-8", method="html").strip() else: result = etree.tounicode(tree, method="html").strip() return strip_outer(result)
def move(self, path, directory): """Move the item at the given path to a new directory """ if six.PY2: path = safe_encode(path, 'utf-8') directory = safe_encode(directory, 'utf-8') npath = self.normalizePath(path) newParentPath = self.normalizePath(directory) parentPath = self.parentPath(npath) filename = npath.split('/')[-1] code = 0 error = '' newCanonicalPath = '{0}/{1}'.format(newParentPath, filename) try: parent = self.getObject(parentPath) except KeyError: error = translate(_(u'filemanager_invalid_parent', default=u'Parent folder not found.'), context=self.request) code = 1 return json.dumps({ 'code': code, 'error': error, 'newPath': self.normalizeReturnPath(newCanonicalPath), }) try: target = self.getObject(newParentPath) except KeyError: error = translate(_(u'filemanager_error_folder_exists', default=u'Destination folder not found.'), context=self.request) code = 1 return json.dumps({ 'code': code, 'error': error, 'newPath': self.normalizeReturnPath(newCanonicalPath), }) if filename not in parent: error = translate(_(u'filemanager_error_file_not_found', default=u'File not found.'), context=self.request) code = 1 elif filename in target: error = translate(_(u'filemanager_error_file_exists', default=u'File already exists.'), context=self.request) code = 1 else: obj = parent[filename] del parent[filename] target[filename] = obj return json.dumps({ 'code': code, 'error': error, 'newPath': self.normalizeReturnPath(newCanonicalPath), })
def createThemeFromTemplate(title, description, baseOn='template'): """Create a new theme from the given title and description based on another theme resource directory """ source = queryResourceDirectory(THEME_RESOURCE_NAME, baseOn) if source is None: raise KeyError("Theme {0:s} not found".format(baseOn)) themeName = getUtility(IURLNormalizer).normalize(title) if six.PY2 and isinstance(themeName, six.text_type): themeName = themeName.encode('utf-8') resources = getOrCreatePersistentResourceDirectory() resources.makeDirectory(themeName) target = resources[themeName] cloneResourceDirectory(source, target) manifest = SafeConfigParser() if MANIFEST_FILENAME in target: if six.PY2: fp = target.openFile(MANIFEST_FILENAME) try: if hasattr(manifest, "read_file"): # backports.configparser manifest.read_file(fp) else: manifest.readfp(fp) finally: fp.close() else: # configparser can only read/write text # but in py3 plone.resource objects are BytesIO objects. fp = target.openFile(MANIFEST_FILENAME) try: data = fp.read() finally: fp.close() manifest.read_string(safe_unicode(data)) if not manifest.has_section('theme'): manifest.add_section('theme') if six.PY2 and isinstance(title, six.text_type): title = title.encode('utf-8') if six.PY2 and isinstance(description, six.text_type): description = description.encode('utf-8') manifest.set('theme', 'title', title) manifest.set('theme', 'description', description) if manifest.has_option('theme', 'prefix'): prefix = u"/++%s++%s" % (THEME_RESOURCE_NAME, themeName) manifest.set('theme', 'prefix', prefix) if manifest.has_option('theme', 'rules'): rule = manifest.get('theme', 'rules') rule_file_name = rule.split('/')[-1] # extract real rules file name rules = u"/++%s++%s/%s" % (THEME_RESOURCE_NAME, themeName, rule_file_name) manifest.set('theme', 'rules', rules) paths_to_fix = [ 'development-css', 'production-css', 'tinymce-content-css', 'development-js', 'production-js' ] for var_path in paths_to_fix: if not manifest.has_option('theme', var_path): continue val = manifest.get('theme', var_path) if not val: continue template_prefix = '++%s++%s/' % (THEME_RESOURCE_NAME, baseOn) if template_prefix in val: # okay, fix val = val.replace(template_prefix, '++%s++%s/' % (THEME_RESOURCE_NAME, themeName)) manifest.set('theme', var_path, val) # plone.resource uses OFS.File which is a BytesIO objects # but configparser can only deal with text (StringIO). # So we need to do this stupid dance to write manifest.cfg tempfile = six.StringIO() manifest.write(tempfile) tempfile.seek(0) data = tempfile.read() tempfile.close() manifestContents = six.BytesIO(safe_encode(data)) target.writeFile(MANIFEST_FILENAME, manifestContents) return themeName
def getInfo(self, path, getSize=False): """Returns information about a single file. Requests with mode "getinfo" will include an additional parameter, "path", indicating which file to inspect. A boolean parameter "getsize" indicates whether the dimensions of the file (if an image) should be returned. """ if six.PY2: path = safe_encode(path, 'utf-8') path = self.normalizePath(path) obj = self.getObject(path) filename = obj.__name__ error = '' errorCode = 0 properties = { 'dateModified': None, } if isinstance(obj, File): properties['dateModified'] = DateTime(obj._p_mtime).strftime('%c') size = obj.get_size() / 1024 if size < 1024: size_specifier = u'kb' else: size_specifier = u'mb' size = size / 1024 properties['size'] = '{0}{1}'.format( size, translate(_(u'filemanager_{0}'.format(size_specifier), default=size_specifier), context=self.request) ) fileType = 'txt' siteUrl = self.portalUrl resourceName = self.resourceDirectory.__name__ preview = '{0}/{1}/images/fileicons/default.png'.format( siteUrl, self.staticFiles ) if IResourceDirectory.providedBy(obj): preview = '{0}/{1}/images/fileicons/_Open.png'.format( siteUrl, self.staticFiles ) fileType = 'dir' path = path + '/' else: fileType = self.getExtension(path, obj) if fileType in self.imageExtensions: preview = '{0}/++{1}++{2}/{3}'.format( siteUrl, self.resourceType, resourceName, path ) elif fileType in self.extensionsWithIcons: preview = '{0}/{1}/images/fileicons/{2}.png'.format( siteUrl, self.staticFiles, fileType ) if isinstance(obj, Image): properties['height'] = obj.height properties['width'] = obj.width return { 'path': self.normalizeReturnPath(path), 'filename': filename, 'fileType': fileType, 'preview': preview, 'properties': properties, 'error': error, 'code': errorCode, }
def export_schema(context): """Export TTW schema """ schema = ttw.serialize_ttw_schema() context.writeDataFile(FILE, safe_encode(schema), 'text/xml') logger.info('Exported schema')