def validate_og_fallback_image(value): """Check if fallback image follows best practices on MIME type, size, dimensions and aspect ratio. """ if value is None: return True filename, data = b64decode_file(value) image = NamedBlobImage(data=data, filename=filename) if image.contentType not in OG_LEAD_IMAGE_MIME_TYPES: raise Invalid(MSG_INVALID_OG_LEAD_IMAGE_MIME_TYPE) if image.getSize() > OG_LEAD_IMAGE_MAX_SIZE: raise Invalid(MSG_INVALID_OG_LEAD_IMAGE_SIZE) width, height = image.getImageSize() if width < OG_LEAD_IMAGE_MIN_WIDTH or height < OG_LEAD_IMAGE_MIN_HEIGHT: raise Invalid(MSG_INVALID_OG_LEAD_IMAGE_DIMENSIONS) aspect_ratio = width / height if aspect_ratio < OG_LEAD_IMAGE_MIN_ASPECT_RATIO: raise Invalid(MSG_INVALID_OG_LEAD_IMAGE_ASPECT_RATIO) return True
def testPublishUpdatesLogo(self): # Test for http://code.simplon.biz/tracker/tno-euphorie/ticket/136 white_gif = ( b"GIF89a\x01\x00\x01\x00\x80\x00\x00\xff\xff\xff\xff\xff\xff," b"\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;" ) black_gif = ( b"GIF89a\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00\xff\xff\xff," b"\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;" ) self.createSurvey() self.sector.logo = NamedBlobImage( data=white_gif, contentType="image/gif", filename="white.gif" ) view = self.survey.restrictedTraverse("@@publish") view.publish() client_sector = self.client.nl["dining"] self.assertEqual(client_sector.logo.data, white_gif) images = client_sector.restrictedTraverse("@@images") white_scale = images.scale("logo", height=100, direction="up").data.data self.sector.logo = NamedBlobImage( data=black_gif, contentType="image/gif", filename="black.gif" ) view.publish() self.assertEqual(client_sector.logo.data, black_gif) images = client_sector.restrictedTraverse("@@images") black_scale = images.scale("logo", height=100, direction="up").data.data self.assertNotEqual(white_scale, black_scale)
def testImage(self): self.folder.invokeFactory('Image', id='image') portal_repository = self.portal_repository img1 = open(os.path.join(PACKAGE_HOME, 'tests/images/img1.png'), 'rb').read() img2 = open(os.path.join(PACKAGE_HOME, 'tests/images/img2.png'), 'rb').read() content = self.folder.image content.image = NamedBlobImage(img1, u'img1.png', u'image/png') content.title = u'content' content.subject = [u'content'] content.description = u'content' content.contributors = [u'content'] content.language = 'content' content.rights = u'content' portal_repository.applyVersionControl(content, comment='save no 1') content.image = NamedBlobImage(img2, u'img2.png', u'image/png') content.title = u'contentOK' content.subject = [u'contentOK'] content.description = u'contentOK' content.contributors = [u'contentOK'] content.language = 'contentOK' content.rights = u'contentOK' portal_repository.save(content, comment='save no 2') obj = portal_repository.retrieve(content, 0).object self.assertEqual(obj.image.data, img1) self.metadata_test_one(obj) obj = portal_repository.retrieve(content, 1).object self.assertEqual(obj.image.data, img2) self.metadata_test_two(obj) portal_repository.revert(content, 0) self.assertEqual(content.image.data, img1) self.metadata_test_one(content)
def setUp(self): self.app = self.layer["app"] self.portal = self.layer["portal"] self.portal_url = self.portal.absolute_url() setRoles(self.portal, TEST_USER_ID, ["Manager"]) self.api_session = RelativeSession(self.portal_url) self.api_session.headers.update({"Accept": "application/json"}) self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) image_file = os.path.join(os.path.dirname(__file__), u"image.png") with open(image_file, "rb") as f: image_data = f.read() self.folder = api.content.create(container=self.portal, type="Folder", title="Normal folder") self.subsite = api.content.create( container=self.portal, type="Subsite", title="Subsite", subsite_header=RichTextValue( raw="<p>header</p>", mimeType="text/html", outputMimeType="text/html", encoding="utf-8", ), subsite_footer=RichTextValue( raw="<p>footer</p>", mimeType="text/html", outputMimeType="text/html", encoding="utf-8", ), subsite_css_class="red", image=NamedBlobImage(data=image_data, contentType="image/png", filename=u"image.png"), subsite_logo=NamedBlobImage(data=image_data, contentType="image/png", filename=u"image.png"), ) self.document_in_subsite = api.content.create( container=self.subsite, type="Document", title="Document in subsite", ) self.document_outside_subsite = api.content.create( container=self.folder, type="Document", title="Document outside subsite", ) commit()
def create_object(self, folder, type_, info): filename = info['name'] name = filename.decode("utf8") chooser = INameChooser(folder) chooser_name = name.lower().replace('aq_', '') newid = chooser.chooseName(chooser_name, folder.aq_parent) # strip metadata from file if (type_ in ('Image', 'File', 'Video', 'Audio') and exiftool is not None and 'tmp_file' in info): try: exiftool(info['tmp_file']) except Exception: logger.warn('Could not strip metadata from file: %s' % info['tmp_file']) fi = open(info['tmp_file'], 'r') try: # Try to determine which kind of NamedBlob we need # This will suffice for standard p.a.contenttypes File/Image # and any other custom type that would have 'File' or 'Image' in # its type name filename = ploneutils.safe_unicode(filename) create_opts = dict(type=type_, id=newid, container=folder) if 'Image' in type_: image = NamedBlobImage(data=fi, filename=filename) try: image.focal_point = [ float(self.request.form.get('focalX')), float(self.request.form.get('focalY')) ] except Exception: pass create_opts['image'] = image else: create_opts['file'] = NamedBlobFile(data=fi, filename=filename) for field in get_upload_fields(): if not field.get('name'): continue name = field['name'] if not self.request.form.get(name): continue if name in ('tags', 'subject'): # tags needs to be converted create_opts['subject'] = self.request.form.get(name).split( ';') else: create_opts[name] = self.request.form.get(name, '') return api.content.create(**create_opts) finally: fi.close()
def testCopyBlobs(self): from zope.copy import copy file = NamedBlobFile() file.data = u'hello, world' image = NamedBlobImage() image.data = 'some image bytes' transaction.commit() file_copy = copy(file) self.assertEqual(file_copy.data, file.data) image_copy = copy(image) self.assertEqual(image_copy.data, image.data)
def test_opened_file_storable(self): data = getFile('image.gif') f = tempfile.NamedTemporaryFile(delete=False) try: path = f.name f.write(data) f.close() with open(path, 'rb') as f: fi = NamedBlobImage(f, filename=u'image.gif') finally: if os.path.exists(path): os.remove(path) self.assertEqual(303, fi.getSize())
def update_featuredimage(context, event): """Update Fetured Image after save content""" if not context.featuredimage_enabled: return page = u'{0}/@@featuredimage'.format(context.absolute_url()) # integration tests don't work with phantomjs if page.startswith('http://nohost/'): return # without this phantomjs look the old page transaction.commit() # get screenshot data = _get_screenshot(page) # save image image = NamedBlobImage() image._setData(data) context.featured_image = image
def test_namedblobimage_field_serialization_doesnt_choke_on_corrupt_image( self): """ Original image url will be None because the original image is corrupted and the created url should be an image scale """ image_data = b"INVALID IMAGE DATA" fn = "test_namedblobimage_field" with patch.object(storage, "uuid4", return_value="uuid_1"): value = self.serialize( fn, NamedBlobImage(data=image_data, contentType=u"image/gif", filename=u"1024x768.gif"), ) self.assertEqual( { u"content-type": u"image/gif", u"download": None, u"filename": u"1024x768.gif", u"height": -1, u"scales": {}, u"size": 18, u"width": -1, }, value, )
def update_file_content(self, info): type_, location = self.get_type_and_location(info) obj = uuidToObject(info['existing_id']) success = False msg = None if obj: if self.sm.checkPermission(ModifyPortalContent, obj): try: if info['field_name'].startswith('tmp_'): self.add_tmp_upload(obj, info) else: fi = open(info['tmp_file'], 'r') filename = ploneutils.safe_unicode(info['name']) if 'Image' in type_: blob = NamedBlobImage(data=fi, filename=filename) else: blob = NamedBlobFile(data=fi, filename=filename) setattr(obj, info['field_name'], blob) success = True except Exception: # could not update content logger.warning('Error updating content', exc_info=True) msg = 'Unknown error' else: msg = 'Invalid permissions' else: success = False msg = 'Object not found' return obj, success, msg
def migrate_schema_fields(self): old_image = self.old.getField('image').get(self.old) if old_image == '': return filename = safe_unicode(old_image.filename) namedblobimage = NamedBlobImage(data=old_image.data, filename=filename) self.new.image = namedblobimage
def migrate_imagefield(src_obj, dst_obj, src_fieldname, dst_fieldname): """ migrate an image field. This field needs to be migrated with an NamedBlobImage instance. """ # get old image data and filename old_image = src_obj.getField(src_fieldname).get(src_obj) if old_image == '': return filename = safe_unicode(old_image.filename) old_image_data = old_image.data if safe_hasattr(old_image_data, 'data'): old_image_data = old_image_data.data # create the new image field namedblobimage = NamedBlobImage(data=old_image_data, filename=filename) # set new field on destination object setattr(dst_obj, dst_fieldname, namedblobimage) # handle a possible image caption field # postulate is the old caption field name is ending by 'Caption' # and the new field name is ending by '_caption' # is this postulate correct ? # should this field not be handle by itself because it will appear in the # old field list ? caption_field = src_obj.getField('%sCaption' % src_fieldname, None) if caption_field: setattr(dst_obj, ('%s_caption' % dst_fieldname), safe_unicode(caption_field.get(src_obj))) logger.info("Migrating image %s" % filename)
def updateOGG(context, normalizedTitle, pt): """ :param context: an object with a ``ogg`` field :type context: usualy a ABC object :param normalizedTitle: used for the blob filename :type normalizedTitle: string :param pt: tool :type pt: portal_tranform tool :returns: nothing, update the ``ogg`` field of the object """ try: oggData = pt.convertTo( 'audio/ogg', context.abc, context=context, annotate=True, ) oggFilename = normalizedTitle + u'.ogg' oggContenType = 'audio/ogg' context.ogg = NamedBlobImage() context.ogg.data = oggData.getData() context.ogg.filename = oggFilename context.ogg.contentType = oggContenType except Exception: msg = u'Failed to create OGG sound' logger.info(msg) annotateObject(context, msg=msg, key='ABC_ERRORS')
def dummy_file(): from plone.namedfile.file import NamedBlobImage path = os.path.join(os.path.dirname(__file__), FILENAME) return NamedBlobImage( data=open(path, 'r').read(), filename=FILENAME )
def dummy_image(): from plone.namedfile.file import NamedBlobImage filename = os.path.join(os.path.dirname(__file__), u'image.jpg') return NamedBlobImage( data=open(filename, 'r').read(), filename=filename )
def test_get_news_item(self): self.portal.invokeFactory('News Item', id='news1', title='News Item 1') image_file = os.path.join(os.path.dirname(__file__), u'image.png') self.portal.news1.image = NamedBlobImage(data=open(image_file, 'r').read(), contentType='image/png', filename=u'image.png') self.portal.news1.image_caption = u'This is an image caption.' transaction.commit() with patch.object(storage, 'uuid4', return_value='uuid1'): response = self.api_session.get(self.portal.news1.absolute_url()) self.assertEqual(response.status_code, 200) self.assertEqual( response.headers.get('Content-Type'), 'application/json', 'When sending a GET request with Content-Type: application/json ' + # noqa 'the server should respond with sending back application/json.' ) self.assertEqual( 'News Item', response.json().get('@type'), "Response should be @type 'News Item', not '{}'".format( response.json().get('@type'))) self.assertEqual(response.json().get('@id'), self.portal.news1.absolute_url()) self.assertEqual('News Item 1', response.json().get('title')) self.assertEqual(u'This is an image caption.', response.json()['image_caption']) self.assertDictContainsSubset( {'download': self.portal_url + u'/news1/@@images/uuid1.png' }, # noqa response.json()['image'])
def create_entry(self, folder, dictNews): ''' Cria news item, realiza transição ''' oId = str(dictNews.get('id')) if not oId in folder.objectIds(): api.content.create(folder, 'News Item', oId, title=dictNews.get('title'), description=dictNews.get('description')) else: return folder[oId] log.info(' - Cria item %s' % (oId)) o = folder[oId] if not o: return for k, v in dictNews.items(): if k in ['title', 'id', 'anexos']: continue if k in ['text']: v = RichTextValue(v, 'text/html', 'text/html') o.text = v if k in ['image']: data = v[0] content_type = v[1] filename = u'image.%s' % (content_type.split('/')[1]) v = NamedBlobImage(data, content_type, filename) o.image = v if v and hasattr(o, k): setattr(o, k, v) o.exclude_from_nav = True api.content.transition(o, 'publish') o.reindexObject() return o
def test_get_content_related_items_without_workflow(self): intids = getUtility(IIntIds) self.portal.invokeFactory("Image", id="imagewf") self.portal.imagewf.title = "Image without workflow" self.portal.imagewf.description = "This is an image" image_file = os.path.join(os.path.dirname(__file__), "image.png") with open(image_file, "rb") as f: image_data = f.read() self.portal.imagewf.image = NamedBlobImage(data=image_data, contentType="image/png", filename="image.png") transaction.commit() self.portal.folder1.doc1.relatedItems = [ RelationValue(intids.getId(self.portal.imagewf)) ] transaction.commit() response = requests.get( self.portal.folder1.doc1.absolute_url(), headers={"Accept": "application/json"}, auth=(SITE_OWNER_NAME, SITE_OWNER_PASSWORD), ) self.assertEqual(response.status_code, 200) self.assertEqual(1, len(response.json()["relatedItems"])) self.assertEqual( [{ "@id": self.portal_url + "/imagewf", "@type": "Image", "description": "This is an image", "review_state": None, "title": "Image without workflow", }], response.json()["relatedItems"], )
def _create_file(self, item, files, title, description, rights): namechooser = INameChooser(self.context) content_type = item.headers.get('Content-Type') filename = safe_unicode(item.filename) data = item.read() id_name = '' title = title and title[0] or filename id_name = namechooser.chooseName(title, self.context) if content_type in IMAGE_MIMETYPES: portal_type = 'Image' wrapped_data = NamedBlobImage(data=data, filename=filename) else: portal_type = 'File' wrapped_data = NamedBlobFile(data=data, filename=filename) self.context.invokeFactory(portal_type, id=id_name, title=title, description=description[0], rights=rights[0]) newfile = self.context[id_name] if portal_type == 'File': if IATFile.providedBy(newfile): newfile.setFile(data, filename=filename) else: newfile.file = wrapped_data elif portal_type == 'Image': if IATImage.providedBy(newfile): newfile.setImage(data, filename=filename) else: newfile.image = wrapped_data newfile.reindexObject() notify(ObjectModifiedEvent(newfile)) return newfile
def migrate_blobimagefield(src_obj, dst_obj, src_fieldname, dst_fieldname): """ migrate an image field. Actually this field needs only to copy the existing NamedBlobImage instance to the new dst_obj, but we do some more in detail and create new fields. """ old_image = getattr(src_obj, src_fieldname) if old_image == '': return filename = safe_unicode(old_image.filename) old_image_data = old_image.data if safe_hasattr(old_image_data, 'data'): old_image_data = old_image_data.data namedblobimage = NamedBlobImage(data=old_image_data, filename=filename) # set new field on destination object setattr(dst_obj, dst_fieldname, namedblobimage) # handle a possible image caption field field = '{0}_caption'.format(src_fieldname) old_image_caption = getattr(src_obj, field, None) if old_image_caption: setattr(dst_obj, ('{0}_caption'.format(dst_fieldname)), safe_unicode(old_image_caption)) logger.info(u'Migrating image {0}'.format(filename))
def test_dexterity_news_item_get(self): self.portal.invokeFactory("News Item", id="newsitem") self.portal.newsitem.title = "My News Item" self.portal.newsitem.description = u"This is a news item" self.portal.newsitem.text = RichTextValue( u"Lorem ipsum", "text/plain", "text/html" ) image_file = os.path.join(os.path.dirname(__file__), u"image.png") fd = open(image_file, "rb") self.portal.newsitem.image = NamedBlobImage( data=fd.read(), contentType="image/png", filename=u"image.png" ) fd.close() self.portal.newsitem.image_caption = u"This is an image caption." import transaction transaction.commit() response = requests.get( self.portal.newsitem.absolute_url(), headers={"Accept": "application/json"}, auth=(SITE_OWNER_NAME, SITE_OWNER_PASSWORD), ) self.assertEqual(200, response.status_code) self.assertEqual(u"newsitem", response.json().get("id")) self.assertEqual(u"GET", response.json().get("method"))
def test_namedblobimage_field_serialization_doesnt_choke_on_corrupt_image( self): """ In Plone >= 5.2 the original image file is not a "scale", so its url is returned as is and we need to check it, but the scales should be empty""" image_data = b"INVALID IMAGE DATA" fn = "test_namedblobimage_field" with patch.object(storage, "uuid4", return_value="uuid_1"): value = self.serialize( fn, NamedBlobImage(data=image_data, contentType=u"image/gif", filename=u"1024x768.gif"), ) obj_url = self.doc1.absolute_url() scale_url_uuid = "uuid_1" self.assertEqual( { u"content-type": u"image/gif", u"download": u"{}/@@images/{}.{}".format(obj_url, scale_url_uuid, "gif"), u"filename": u"1024x768.gif", u"height": -1, u"scales": {}, u"size": 18, u"width": -1, }, value, )
def prefill_image_types_dexterity(kwargs): import random import string image = random_image() filename = u'{}.png'.format(''.join( random.choice(string.ascii_lowercase) for _ in range(6))) kwargs['image'] = NamedBlobImage(data=image, filename=filename)
def test_namedblobimage_field_serialization_returns_dict(self): image_file = os.path.join(os.path.dirname(__file__), u'1024x768.gif') with open(image_file, 'rb') as f: image_data = f.read() fn = 'test_namedblobimage_field' with patch.object(storage, 'uuid4', return_value='uuid_1'): value = self.serialize( fn, NamedBlobImage( data=image_data, contentType=u'image/gif', filename=u'1024x768.gif' ) ) self.assertTrue(isinstance(value, dict), 'Not a <dict>') scale_url_uuid = 'uuid_1' obj_url = self.doc1.absolute_url() download_url = u'{}/@@images/{}.{}'.format( obj_url, scale_url_uuid, GIF_SCALE_FORMAT ) scales = { u'listing': { u'download': download_url, u'width': 16, u'height': 12}, u'icon': { u'download': download_url, u'width': 32, u'height': 24}, u'tile': { u'download': download_url, u'width': 64, u'height': 48}, u'thumb': { u'download': download_url, u'width': 128, u'height': 96}, u'mini': { u'download': download_url, u'width': 200, u'height': 150}, u'preview': { u'download': download_url, u'width': 400, u'height': 300}, u'large': { u'download': download_url, u'width': 768, u'height': 576}, } self.assertEqual({ u'filename': u'1024x768.gif', u'content-type': u'image/gif', u'size': 1514, u'download': download_url, u'width': 1024, u'height': 768, u'scales': scales}, value)
def populate_with_object(self, obj): # check permissions super(ImageTile, self).populate_with_object(obj) data_mgr = ITileDataManager(self) data_mgr.set({'image': NamedBlobImage(obj.getImage().data)})
def handle_storage(self): gsettings = self.gsettings storage_dir = self.storage_dir settings = self.settings context = self.context # save lead image if available if ILeadImage.providedBy(self.context): path = os.path.join(storage_dir, 'large') filename = None for dump_filename in os.listdir(path): if dump_filename.startswith('dump_1.'): filename = dump_filename break filepath = os.path.join(path, filename) tmppath = '%s.tmp' % (filepath) # NamedBlobImage eventually calls blob.consume, # destroying the image, so we need to make a temporary copy. shutil.copyfile(filepath, tmppath) fi = open(tmppath) self.context.image = NamedBlobImage( fi, filename=filename.decode('utf8')) fi.close() if self.gsettings.storage_type == 'Blob': logger.info('setting blob data for %s' % repr(context)) # go through temp folder and move items into blob storage files = OOBTree() for size in ('large', 'normal', 'small'): path = os.path.join(storage_dir, size) for filename in os.listdir(path): filepath = os.path.join(path, filename) filename = '%s/%s' % (size, filename) files[filename] = saveFileToBlob(filepath) if self.settings.enable_indexation: textfilespath = os.path.join(storage_dir, TEXT_REL_PATHNAME) for filename in os.listdir(textfilespath): filepath = os.path.join(textfilespath, filename) filename = '%s/%s' % (TEXT_REL_PATHNAME, filename) files[filename] = saveFileToBlob(filepath) # Store converted PDF dump_pdf_path = os.path.join(storage_dir, DUMP_FILENAME) filename = 'pdf/%s' % DUMP_FILENAME files[filename] = saveFileToBlob(dump_pdf_path) settings.blob_files = files shutil.rmtree(storage_dir) # check for old storage to remove... Just in case. old_storage_dir = os.path.join(gsettings.storage_location, context.UID()) if os.path.exists(old_storage_dir): shutil.rmtree(old_storage_dir) else: # if settings used to be blob, delete file data if settings.storage_type == 'Blob' and settings.blob_files: del settings._metadata['blob_files']
def updateSVG(context, normalizedTitle, pt): """ :param context: an object with ``abc`` and ``svgscore`` fields :type context: usualy a ABC object :param normalizedTitle: used for the blob filename :type normalizedTitle: string :param pt: tool :type pt: portal_tranform tool :returns: nothing, update the ``svgscore`` field of the object """ try: svgData = pt.convertTo( 'image/svg+xml', context.abc, context=context, annotate=True ) svgFilename = normalizedTitle + u'.svg' svgContenType = 'image/svg+xml' context.svgscore = NamedBlobImage() context.svgscore.data = svgData.getData() context.svgscore.filename = svgFilename context.svgscore.contentType = svgContenType except Exception: msg = u'Failed to create SVG score' logger.info(msg) annotateObject(context, msg=msg, key='ABC_ERRORS')
def get_image(self, item): image_url = None if 'has_lead_image' in item: if item['has_lead_image']: image_url = 'https://%s%s/@@images/image' % (AGSCI_DOMAIN, item.get('path')) else: links = item.get('links', []) image_links = [ x.get('href', '') for x in links if x.get('rel', None) in ('enclosure', ) ] if image_links: image_url = image_links[0] if image_url: image_data = self.download_image(image_url) filename = image_url.split('/')[-1].split('?')[0] if filename: filename = safe_unicode(filename) else: filename = u'image' if image_data: return NamedBlobImage(filename=filename, data=image_data)
def updatePDF(context, normalizedTitle, pt): """ :param context: an object with a ``pdfscore`` field :type context: usualy a ABC object :param normalizedTitle: used for the blob filename :type normalizedTitle: string :param pt: tool :type pt: portal_tranform tool :returns: nothing, update the ``pdfscore`` field of the object """ try: pdfData = pt.convertTo( 'application/pdf', context.abc, context=context, annotate=True, ) pdfFilename = normalizedTitle + u'.pdf' pdfContenType = 'application/pdf' context.pdfscore = NamedBlobImage() context.pdfscore.data = pdfData.getData() context.pdfscore.filename = pdfFilename context.pdfscore.contentType = pdfContenType except Exception: msg = u'Failed to create PDF score' logger.info(msg) annotateObject(context, msg=msg, key='ABC_ERRORS')
def test_lead_image(self): from plone.namedfile.file import NamedBlobImage filename = u'logo-plone-ok.png' self.newsitem.image = NamedBlobImage(data=get_file(filename), filename=filename) self.newsitem.image_caption = u'Mais amor, por favor!' amp = etree.HTML(self.view()) lead_image = amp.find('.//figure/amp-img') self.assertIsNotNone(lead_image) self.assertTrue(lead_image.attrib['src'].endswith(filename)) self.assertEqual(lead_image.attrib['layout'], 'responsive') self.assertEqual(lead_image.attrib['width'], '231') self.assertEqual(lead_image.attrib['height'], '60') self.assertEqual( amp.find('.//figure/figcaption').text, 'Mais amor, por favor!') # lead image information in metadata metadata = self._get_metadata_as_json(amp) self.assertIn('image', metadata) metadata = metadata['image'] # shortcut self.assertEqual(metadata['@type'], u'ImageObject') url = u'lorem-ipsum/@@download/image/{0}'.format(filename) self.assertTrue(metadata['url'].endswith(url)) self.assertEqual(metadata['width'], 231) self.assertEqual(metadata['height'], 60)
def test_basic_tile_purge_cache(self): provideHandler(queuePurge) request = self.request alsoProvides(request, IAttributeAnnotatable) setRequest(request) registry = queryUtility(IRegistry) registry.registerInterface(ICachePurgingSettings) provideUtility(registry, IRegistry) settings = registry.forInterface(ICachePurgingSettings) settings.enabled = True settings.cachingProxies = ('http://*****:*****@@collective.cover.basic/test', '/c1/@@collective.cover.basic/test/@@images/image', '/c1/@@collective.cover.basic/test/@@images/icon', '/c1/@@collective.cover.basic/test/@@images/mini', '/c1/@@collective.cover.basic/test/@@images/large', '/c1/@@collective.cover.basic/test/@@images/listing', '/c1/@@collective.cover.basic/test/@@images/thumb', '/c1/@@collective.cover.basic/test/@@images/preview', '/c1/@@collective.cover.basic/test/@@images/tile']), IAnnotations(request)['plone.cachepurging.urls'])
def ImportImage(self, node): """ Import a base64 encoded image from an XML node. :param node: lxml.objectified XML node of image element :rtype: (:py:class:`NamedImage`, unicode) tuple """ filename = attr_unicode(node, "filename") contentType = node.get("content-type", None) if not filename: basename = u"image%d.%%s" % random.randint(1, 2 ** 16) if contentType and "/" in contentType: filename = basename % contentType.split(u"/")[1] else: filename = basename % u"jpg" image = NamedBlobImage(data=node.text.decode("base64"), contentType=contentType, filename=filename) if image.contentType is None and image.filename: image.contentType = mimetypes.guess_type(image.filename)[0] return (image, attr_unicode(node, "caption"))
def create_lead_image(size=(800, 450), color="blue"): """ Creates an memory object containing an image. Expects a size tuple and PIL color. :param size: tuple of ints (width, height) default (800, 450) :param color: String or PIL color (r,g,b) tuple. :return: NamedBlobImage """ # Create an image. im = Image.new("RGB", size, color=color) # Draw some lines draw = ImageDraw.Draw(im) color = ImageColor.getrgb(color) for i in range(9): factor = choice(range(8, 18, 1)) / 10.0 stroke_color = ( int(min(color[0] * factor, 255)), int(min(color[1] * factor, 255)), int(min(color[2] * factor, 255)), ) draw.line( [ (choice(range(0, size[0])), choice(range(0, size[1]))), (choice(range(0, size[0])), choice(range(0, size[1]))) ], fill=stroke_color, width=int(size[1] / 5) ) # 'Save' the file. sio = cStringIO.StringIO() im.save(sio, format="PNG") sio.seek(0) # Create named blob image nbi = NamedBlobImage() nbi.data = sio.read() nbi.filename = u"example.png" return nbi
def test_filechunk_storable(self): fi = NamedBlobImage(FileChunk(getFile('image.gif').read()), filename=u'image.gif') self.assertEqual(303, fi.getSize())
def handleApply(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return utils._send_emails = False try: en_folder = self.context.restrictedTraverse('en') if 'organisations' in en_folder: org_folder = en_folder.restrictedTraverse('organisations') else: org_folder = content.create(en_folder, type='osha.hwccontent.organisationfolder', title='Organisations') if 'focalpoints' in en_folder: fop_folder = en_folder.restrictedTraverse('focalpoints') else: fop_folder = content.create(en_folder, type='osha.hwccontent.organisationfolder', title='Focalpoints') type_mapping = { u'Organisation': { 'type': 'osha.hwccontent.organisation', 'schema': dict(getFieldsInOrder(IOrganisation)), 'folder': org_folder, 'wf_actions': ('approve_phase_1',), }, u'Focalpoint': { 'type': 'osha.hwccontent.focalpoint', 'schema': dict(getFieldsInOrder(IFocalPoint)), 'folder': fop_folder, 'wf_actions': ('publish',), } } count = 0 for data in json.loads(data['json']): # Only keep the data that's in the main schema: type_info = type_mapping[data['_type']] schema = type_info['schema'] fields = {} if data['title'].startswith('MC-'): continue for name, field in schema.items(): if name in data: value = data[name] if value and INamedImageField.providedBy(field): content_type = data.get('_%s_content_type' % name, '') filename = data.get('_%s_filename' % name , None) value = NamedBlobImage(base64.b64decode(value), str(content_type), filename) elif value and IRichText.providedBy(field): content_type = data.get('_%s_content_type', None) value = RichTextValue(value, mimeType=content_type) elif name.find("email") >= 0: value = value.strip() fields[name] = value new_obj = content.create(container=type_info['folder'], type= type_info['type'], id=data['id'], **fields) for transition in type_info['wf_actions']: try: content.transition(new_obj, transition) except Exception: logger.exception('Could not execute %s transition for %s' % (transition, '/'.join(new_obj.getPhysicalPath()))) logger.info('Imported %s' % new_obj.getId()) count += 1 # Set status on this form page self.status = "%s partners imported" % count except Exception: # Enable emails again: utils._send_emails = True raise
def test_str_storable(self): fi = NamedBlobImage(getFile('image.gif'), filename=u'image.gif') self.assertEqual(303, fi.getSize())
def test_pdata_storable(self): pdata = Pdata(getFile('image.gif').read()) fi = NamedBlobImage(pdata, filename=u'image.gif') self.assertEqual(303, fi.getSize())
def importContent(self): # Grab the "force" parameter from the URL, and convert to boolean. # If this is true, everyone will be updated. force_update = not not self.request.get('force', False) # Initialize the return value list rv = [] # Get a list of the people people = self.getPeople() # Count total people, and initialize counter total_people = len(people) counter = 0 # Log progress self.log("Downloaded data, %d entries" % total_people) # Get listing of valid classifications from current directory valid_classifications = [x.value for x in ClassificationsVocabulary()(self.context)] # Add other classifications that are OK to import valid_classifications.extend([ 'Adjunct and Affiliate Faculty', 'Emeritus and Retired Faculty', 'Emeritus Professors and Retirees', 'Adjunct & Retired Faculty', 'Emeritus Faculty', 'Emeriti and Retired', 'Assistant to the Director', 'Retired and Emeritus Faculty', 'District Directors', ]) # Iterate through contents for i in people: # Increment counter counter = counter + 1 # Set 'product_type' as 'type' i['product_type'] = i.get('type', None) # If we were passed a URL, don't do a classification check if self.person_url: pass # If the person is not an employee with a valid classification, skip # this record. elif not set(i.get('directory_classifications', [])) & set(valid_classifications): continue # Create content importer from person JSON data v = self.content_importer(i) # Check for person existing in directory (import_path) and create or # update appropriately if v.data.get_id in self.import_path.objectIds(): # Update item = self.import_path[v.data.get_id] # Only update if feed last updated date is greater than the item # last updated date. If a "force" parameter is provided in the # URL, all objects will be updated. if force_update or DateTime(v.data.modified) > item.modified(): item = self.updateObject(item, v) # Log progress self.log("Updated %s" % v.data.get_id) else: # Log progress self.log("Skipped %s" % v.data.get_id) continue else: # Create item = self.createObject(self.import_path, v) # Log progress self.log("Created %s" % v.data.get_id) # Set expiration date if v.data.expires: expires = DateTime(v.data.expires) item.setExpirationDate(expires) # Set Image image_url = i.get('image_url', None) if image_url: img = NamedBlobImage() img.data = urllib2.urlopen(image_url).read() item.leadimage = img # Set text field for bio. Note this is not a RichTextValue, since # it's a field inherited from another schema if v.data.html: item.bio = v.data.html # Finalize item self.finalize(item) # Append the data structure converted from the JSON data to rv rv.append(json.loads(self.getJSON(item))) # Log progress self.log("Done with %s, %d/%d" % (v.data.get_id, counter, total_people)) # Deactivate people who are expired and active self.deactivateExpiredPeople() # Return a full JSON dump of the updated data return json.dumps(rv, indent=4, sort_keys=True)
def onVideoSave(context, event, force=False): # Updated flag updated = False # Check if we have missing fields has_leadimage = not not ILeadImageMarker(context).has_leadimage has_duration = not not VideoDataAdapter(context).getDuration() has_channel = not not VideoDataAdapter(context).getVideoChannel() has_aspect_ratio = not not VideoDataAdapter(context).getVideoAspectRatio() has_effective_date = not not context.effective_date # If 'force' is true, or doesn't have a lead image and duration. if force or not has_leadimage or not has_duration \ or not has_channel or not has_aspect_ratio \ or not has_effective_date: # Get the API data data = getDataForYouTubeVideo(context) # Lead Image (if force or not exists) if force or not has_leadimage: # Get the image data via the YouTube API # (will be binary data) image_data = getImageForYouTubeVideo(data) # Set the lead image if we retrieved it if image_data: filename = '%s-leadimage' % context.getId() field = NamedBlobImage(filename.encode('utf-8')) field.data = image_data context.leadimage = field updated = True # Duration (if force or not exists) if force or not has_duration: # Get the duration from the API data # (will be integer) duration = data.get('duration', None) # If there's a duration, set it. if duration: VideoDataAdapter(context).setDuration(duration) updated = True # Channel (if force or not exists) if force or not has_channel: # Get the channel id from the API data # (will be string) channel_id = data.get('channel_id', None) # If there's a channel id, set it. if channel_id: VideoDataAdapter(context).setVideoChannel(channel_id) updated = True # Aspect Ratio (if force or not exists) if force or not has_aspect_ratio: # Get the aspect_ratio from the API data # (will be string) aspect_ratio = data.get('aspect_ratio', None) # If there's a Aspect Ratio, set it. if aspect_ratio: VideoDataAdapter(context).setVideoAspectRatio(aspect_ratio) updated = True # Published date if force or not has_effective_date: try: if data['effective']: effective_date = DateTime(data['effective']) context.setEffectiveDate(effective_date) updated = True except: pass # If we updated a value, reindex the object if updated: context.reindexObject()