def test_mimetype_svg(self): content = base64.b64decode(SVG) mimetype = guess_mimetype(content, default='test') self.assertTrue(mimetype.startswith('image/svg')) # Tests that whitespace padded SVG are not detected as SVG mimetype = guess_mimetype(b" " + content, default='test') self.assertNotIn("svg", mimetype)
def _binary_record_content(self, record, field='datas', filename=None, filename_field='name', default_mimetype='application/octet-stream'): model = record._name mimetype = 'mimetype' in record and record.mimetype or False content = None filehash = 'checksum' in record and record['checksum'] or False field_def = record._fields[field] if field_def.type == 'binary' and field_def.attachment: field_attachment = self.env['ir.attachment'].sudo().search_read( domain=[('res_model', '=', model), ('res_id', '=', record.id), ('res_field', '=', field)], fields=['datas', 'mimetype', 'checksum'], limit=1) if field_attachment: mimetype = field_attachment[0]['mimetype'] content = field_attachment[0]['datas'] filehash = field_attachment[0]['checksum'] if not content: content = record[field] or '' # filename default_filename = False if not filename: if filename_field in record: filename = record[filename_field] if not filename: default_filename = True filename = "%s-%s-%s" % (record._name, record.id, field) if not mimetype: try: decoded_content = base64.b64decode(content) except base64.binascii.Error: # if we could not decode it, no need to pass it down: it would crash elsewhere... return (404, [], None) mimetype = guess_mimetype(decoded_content, default=default_mimetype) # extension _, existing_extension = os.path.splitext(filename) if not existing_extension or default_filename: extension = mimetypes.guess_extension(mimetype) if extension: filename = "%s%s" % (filename, extension) if not filehash: filehash = '"%s"' % hashlib.md5( pycompat.to_text(content).encode('utf-8')).hexdigest() status = 200 if content else 404 return status, content, filename, mimetype, filehash
def _read_file(self, options): """ Dispatch to specific method to read file content, according to its mimetype or file type :param options : dict of reading options (quoting, separator, ...) """ self.ensure_one() # guess mimetype from file content mimetype = guess_mimetype(self.file or b'') (file_extension, handler, req) = FILE_TYPE_DICT.get(mimetype, (None, None, None)) if handler: try: return getattr(self, '_read_' + file_extension)(options) except Exception: _logger.warn( "Failed to read file '%s' (transient id %d) using guessed mimetype %s", self.file_name or '<unknown>', self.id, mimetype) # try reading with user-provided mimetype (file_extension, handler, req) = FILE_TYPE_DICT.get(self.file_type, (None, None, None)) if handler: try: return getattr(self, '_read_' + file_extension)(options) except Exception: _logger.warn( "Failed to read file '%s' (transient id %d) using user-provided mimetype %s", self.file_name or '<unknown>', self.id, self.file_type) # fallback on file extensions as mime types can be unreliable (e.g. # software setting incorrect mime types, or non-installed software # leading to browser not sending mime types) if self.file_name: p, ext = os.path.splitext(self.file_name) if ext in EXTENSIONS: try: return getattr(self, '_read_' + ext[1:])(options) except Exception: _logger.warn( "Failed to read file '%s' (transient id %s) using file extension", self.file_name, self.id) if req: raise ImportError( _("Unable to load \"{extension}\" file: requires Python module \"{modname}\"" ).format(extension=file_extension, modname=req)) raise ValueError( _("Unsupported file format \"{}\", import only supports CSV, ODS, XLS and XLSX" ).format(self.file_type))
def _binary_ir_attachment_redirect_content( cls, record, default_mimetype='application/octet-stream'): # mainly used for theme images attachemnts status = content = filename = filehash = None mimetype = getattr(record, 'mimetype', False) if record.type == 'url' and record.url: # if url in in the form /somehint server locally url_match = re.match("^/(\w+)/(.+)$", record.url) if url_match: module = url_match.group(1) module_path = get_module_path(module) module_resource_path = get_resource_path( module, url_match.group(2)) if module_path and module_resource_path: module_path = os.path.join( os.path.normpath(module_path), '') # join ensures the path ends with '/' module_resource_path = os.path.normpath( module_resource_path) if module_resource_path.startswith(module_path): with open(module_resource_path, 'rb') as f: content = base64.b64encode(f.read()) status = 200 filename = os.path.basename(module_resource_path) mimetype = guess_mimetype(base64.b64decode(content), default=default_mimetype) filehash = '"%s"' % hashlib.md5( pycompat.to_text(content).encode( 'utf-8')).hexdigest() if not content: status = 301 content = record.url return status, content, filename, mimetype, filehash
def test_gif(self): self.assertEqual(guess_mimetype(contents('gif')), 'image/gif')
def test_zip(self): self.assertEqual(guess_mimetype(contents('zip')), 'application/zip')
def test_ods(self): self.assertEqual(guess_mimetype(contents('ods')), 'application/vnd.oasis.opendocument.spreadsheet')
def test_odt(self): self.assertEqual(guess_mimetype(contents('odt')), 'application/vnd.oasis.opendocument.text')
def test_default_mimetype(self): mimetype = guess_mimetype(b'', default='test') # if available, python-magic returns application/x-empty self.assertIn(mimetype, ('test', 'application/x-empty'))
def test_doc(self): self.assertEqual(guess_mimetype(contents('doc')), 'application/msword')
def test_mimetype_gif(self): content = base64.b64decode(GIF) mimetype = guess_mimetype(content, default='test') self.assertEqual(mimetype, 'image/gif')
def test_mimetype_jpg(self): content = base64.b64decode(JPG) mimetype = guess_mimetype(content, default='test') self.assertEqual(mimetype, 'image/jpeg')
def test_mimetype_bmp(self): content = base64.b64decode(BMP) mimetype = guess_mimetype(content, default='test') # mimetype should match image/bmp, image/x-ms-bmp, ... self.assertRegexpMatches(mimetype, r'image/.*\bbmp')
def test_mimetype_octet_stream(self): mimetype = guess_mimetype(b'\0') self.assertEqual(mimetype, 'application/octet-stream')
def test_jpeg(self): self.assertEqual(guess_mimetype(contents('jpg')), 'image/jpeg')
def test_unknown(self): self.assertEqual(guess_mimetype(contents('csv')), 'application/octet-stream')
def test_xls(self): self.assertEqual(guess_mimetype(contents('xls')), 'application/vnd.ms-excel')
def test_docx(self): self.assertEqual( guess_mimetype(contents('docx')), 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' )
def test_xlsx(self): self.assertEqual( guess_mimetype(contents('xlsx')), 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' )
def save_unsplash_url(self, unsplashurls=None, **kwargs): """ unsplashurls = { image_id1: { url: image_url, download_url: download_url, }, image_id2: { url: image_url, download_url: download_url, }, ..... } """ def slugify(s): ''' Keeps only alphanumeric characters, hyphens and spaces from a string. The string will also be truncated to 1024 characters max. :param s: the string to be filtered :return: the sanitized string ''' return "".join([c for c in s if c.isalnum() or c in list("- ")])[:1024] if not unsplashurls: return [] uploads = [] Attachments = request.env['ir.attachment'] query = kwargs.get('query', '') query = slugify(query) res_model = kwargs.get('res_model', 'ir.ui.view') if res_model != 'ir.ui.view' and kwargs.get('res_id'): res_id = int(kwargs['res_id']) else: res_id = None for key, value in unsplashurls.items(): url = value.get('url') try: if not url.startswith('https://images.unsplash.com/'): logger.exception("ERROR: Unknown Unsplash URL!: " + url) raise Exception(_("ERROR: Unknown Unsplash URL!")) req = requests.get(url) if req.status_code != requests.codes.ok: continue # get mime-type of image url because unsplash url dosn't contains mime-types in url image_base64 = base64.b64encode(req.content) except requests.exceptions.ConnectionError as e: logger.exception("Connection Error: " + str(e)) continue except requests.exceptions.Timeout as e: logger.exception("Timeout: " + str(e)) continue image_base64 = tools.image_process(image_base64, verify_resolution=True) mimetype = guess_mimetype(base64.b64decode(image_base64)) # append image extension in name query += mimetypes.guess_extension(mimetype) or '' # /unsplash/5gR788gfd/lion url_frags = ['unsplash', key, query] attachment = Attachments.create({ 'name': '_'.join(url_frags), 'url': '/' + '/'.join(url_frags), 'mimetype': mimetype, 'datas': image_base64, 'public': res_model == 'ir.ui.view', 'res_id': res_id, 'res_model': res_model, }) attachment.generate_access_token() uploads.append(attachment._get_media_info()) # Notifies Unsplash from an image download. (API requirement) self._notify_download(value.get('download_url')) return uploads
def test_default_mimetype_empty(self): mimetype = guess_mimetype(b'') # coffice implementation returns application/octet-stream by default # if available, python-magic returns application/x-empty self.assertIn(mimetype, ('application/octet-stream', 'application/x-empty'))