def testPruneMemberDataContents(self): # Only test what is not already tested elswhere self.memberdata._setPortrait( Image(id=default_user, file=dummy.File(), title=''), default_user) self.memberdata._setPortrait( Image(id=default_user, file=dummy.File(), title=''), 'dummy') self.memberdata.pruneMemberDataContents() self.assertEqual(len(self.memberdata.portraits), 1)
def PUT_factory( self, name, typ, body ): """ Dispatcher for PUT requests to non-existent IDs. Returns an object of the appropriate type (or None, if we don't know what to do). """ major, minor = typ.split('/', 1) if major == 'image': return Image( id=name , title='' , file='' , content_type=typ ) if major == 'text': if minor == 'x-python': return PythonScript( id=name ) if minor in ('html', 'xml'): return ZopePageTemplate( name ) return DTMLMethod( __name__=name ) return None
def _getPortrait(self, member_id): """ return member_id's portrait if you can. If it's not possible, just try to fetch a 'portait' property from the underlying user source, then create a portrait from it. """ # fetch the 'portrait' property Log(LOG_DEBUG, "trying to fetch the portrait for the given member id") portrait = self._former_getPortrait(member_id) if portrait: Log(LOG_DEBUG, "Returning the old-style portrait:", portrait, "for", member_id) return portrait # Try to find a portrait in the user source member = self.portal_membership.getMemberById(member_id) portrait = member.getUser().getProperty('portrait', None) if not portrait: Log(LOG_DEBUG, "No portrait available in the user source for", member_id) return None # Convert the user-source portrait into a plone-complyant one Log(LOG_DEBUG, "Converting the portrait", type(portrait)) portrait = Image(id=member_id, file=portrait, title='') membertool = self.portal_memberdata membertool._setPortrait(portrait, member_id) # Re-call ourself to retreive the real portrait Log(LOG_DEBUG, "Returning the real portrait") return self._former_getPortrait(member_id)
def testSetPortrait(self): self.memberdata._setPortrait( Image(id=default_user, file=dummy.File(), title=''), default_user) self.assertEqual( self.memberdata._getPortrait(default_user).getId(), default_user) self.assertEqual( self.memberdata._getPortrait(default_user).meta_type, 'Image')
def saveTile(self, image, scaleNumber, column, row): """ save the cropped region """ w, h = image.size if w != 0 and h != 0: tileFileName = self.getTileFileName(scaleNumber, column, row) tileContainerName = self.getAssignedTileContainerName( tileFileName=tileFileName) tileImageData = StringIO() image.save(tileImageData, 'JPEG', quality=self.qualitySetting) tileImageData.seek(0) if hasattr(self._v_saveFolderObject, tileContainerName): tileFolder = getattr(self._v_saveFolderObject, tileContainerName) # if an image of this name already exists, delete and replace it. if hasattr(tileFolder, tileFileName): tileFolder._delObject(tileFileName) # finally, save the image data as a Zope Image object tileFolder._setObject( tileFileName, Image(tileFileName, '', '', 'image/jpeg', '')) tileFolder._getOb(tileFileName).manage_upload(tileImageData) self._v_transactionCount += 1 if self._v_transactionCount % 10 == 0: transaction.savepoint() return
def setImage(self, value, **kwargs): field = self.getField('image') # If the image exists in portal memberdata's portraits folder, delete it md = getToolByName(self, 'portal_memberdata') if self.id in md.portraits: md.portraits._delObject(self.id) # Assign the image to the field field.set(self, value) # If there is an image value (not the empty string that seems to get sent on # object creation) # and it's not a delete command, create a member portrait if value and value != 'DELETE_IMAGE': # Add the new portrait # md.portraits._setObject(id=self.id, object=self.getImage()) raw_image = StringIO() raw_image.write(str(self.getRawImage().data)) raw_image.seek(0) md.portraits._setObject(id=self.id, object=Image(id=self.id, file=raw_image, title='')) raw_image.close()
def __init__(self, context): """ Load MAX avatar in portrait. """ super(EnhancedUserDataPanelAdapter, self).__init__(context) try: from plone.protect.interfaces import IDisableCSRFProtection alsoProvides(self.request, IDisableCSRFProtection) except: pass maxclient, settings = getUtility(IMAXClient)() foto = maxclient.people[self.context.id].avatar imageUrl = foto.uri portrait = urllib.urlretrieve(imageUrl) scaled, mimetype = convertSquareImage(portrait[0]) if scaled: portrait = Image(id=self.context.id, file=scaled, title='') membertool = getToolByName(self.context, 'portal_memberdata') membertool._setPortrait(portrait, self.context.id) import transaction transaction.commit()
def test_get_commenter_portrait(self): # Add a user with a member image self.membershipTool.addMember('jim', 'Jim', ['Member'], []) self.memberdata._setPortrait(Image( id='jim', file=dummy.File(), title='' ), 'jim') self.assertEqual( self.memberdata._getPortrait('jim').getId(), 'jim' ) self.assertEqual( self.memberdata._getPortrait('jim').meta_type, 'Image' ) # Add a conversation with a comment conversation = IConversation(self.portal.doc1) comment = createObject('plone.Comment') comment.text = 'Comment text' comment.Creator = 'Jim' comment.author_username = '******' conversation.addComment(comment) # Call get_commenter_portrait method of the viewlet self.viewlet.update() portrait_url = self.viewlet.get_commenter_portrait('jim') # Check if the correct member image URL is returned self.assertEqual( portrait_url, 'http://nohost/plone/portal_memberdata/portraits/jim' )
def test_exportXML(self): from OFS.Folder import Folder from OFS.Image import Image from OFS.XMLExportImport import exportXML connection, app = self._makeJarAndRoot() data = open(imagedata, 'rb') sub = Folder('sub') app._setObject('sub', sub) img = Image('image', '', data, 'image/gif') sub._setObject('image', img) img._setProperty('prop1', 3.14159265359, 'float') img._setProperty('prop2', 1, 'int') img._setProperty('prop3', 2L**31-1, 'long') img._setProperty('prop4', 'xxx', 'string') img._setProperty('prop5', ['xxx', 'zzz'], 'lines') img._setProperty('prop6', u'xxx', 'unicode') img._setProperty('prop7', [u'xxx', u'zzz'], 'ulines') img._setProperty('prop8', '<&>', 'string') img._setProperty('prop9', u'<&>', 'unicode') img._setProperty('prop10', '<]]>', 'string') img._setProperty('prop11', u'<]]>', 'unicode') img._setProperty('prop12', u'£', 'unicode') transaction.savepoint(optimistic=True) oid = sub._p_oid handle, path = tempfile.mkstemp(suffix='.xml') try: ostream = os.fdopen(handle,'wb') data = exportXML(connection, oid, ostream) ostream.close() finally: os.remove(path)
def _createObjectByType(self, name, body, content_type): encoding = self.getEncoding() or 'utf-8' if six.PY2 and isinstance(body, six.text_type): body = body.encode(encoding) if name.endswith('.py'): ob = PythonScript(name) ob.write(body) return ob if name.endswith('.dtml'): ob = DTMLDocument('', __name__=name) ob.munge(body) return ob if content_type in ('text/html', 'text/xml'): return ZopePageTemplate(name, body, content_type=content_type) if isinstance(body, six.text_type): body = body.encode(encoding) if content_type[:6] == 'image/': return Image(name, '', body, content_type=content_type) return File(name, '', body, content_type=content_type)
def set_member_portrait(self, user, portrait): portal = getSite() portal_membership = getToolByName(portal, "portal_membership") safe_id = portal_membership._getSafeMemberId(user.getId()) if portrait is None: previous = portal_membership.getPersonalPortrait(safe_id) default_portrait_value = getattr(portal, default_portrait, None) if aq_inner(previous) != aq_inner(default_portrait_value): portal_membership.deletePersonalPortrait(str(safe_id)) return content_type = "application/octet-stream" filename = None content_type = portrait.get("content-type", content_type) filename = portrait.get("filename", filename) data = portrait.get("data") if isinstance(data, six.text_type): data = data.encode("utf-8") if "encoding" in portrait: data = codecs.decode(data, portrait["encoding"]) if portrait.get("scale", False): # Only scale if the scale (default Plone behavior) boolean is set # This should be handled by the core in the future scaled, mimetype = scale_image(six.BytesIO(data)) else: # Normally, the scale and cropping is going to be handled in the # frontend scaled = data portrait = Image(id=safe_id, file=scaled, title="") membertool = getToolByName(self, "portal_memberdata") membertool._setPortrait(portrait, safe_id)
def _createObjectByType( self, name, body, content_type ): if isinstance( body, unicode ): encoding = self.getEncoding() if encoding is None: body = body.encode() else: body = body.encode( encoding ) if name.endswith('.py'): ob = PythonScript( name ) ob.write( body ) elif name.endswith('.dtml'): ob = DTMLDocument( '', __name__=name ) ob.munge( body ) elif content_type in ('text/html', 'text/xml' ): ob = ZopePageTemplate( name, body , content_type=content_type ) elif content_type[:6]=='image/': ob=Image( name, '', body, content_type=content_type ) else: ob=File( name, '', body, content_type=content_type ) return ob
def changeMemberPortrait(self, portrait, id=None): """update the portait of a member. We URL-quote the member id if needed. Note that this method might be called by an anonymous user who is getting registered. This method will then be called from plone.app.users and this is fine. When called from restricted python code or with a curl command by a hacker, the declareProtected line will kick in and prevent use of this method. """ authenticated_id = self.getAuthenticatedMember().getId() if not id: id = authenticated_id safe_id = self._getSafeMemberId(id) if authenticated_id and id != authenticated_id: # Only Managers can change portraits of others. if not _checkPermission(ManageUsers, self): raise Unauthorized if portrait and portrait.filename: scaled, mimetype = scale_image(portrait) portrait = Image(id=safe_id, file=scaled, title='') membertool = getToolByName(self, 'portal_memberdata') membertool._setPortrait(portrait, safe_id)
def _createObjectByType( self, name, body, content_type ): if name.endswith('.py'): ob = PythonScript( name ) ob.write( body ) elif name.endswith('.dtml'): ob = DTMLDocument( '', __name__=name ) ob.munge( body ) elif content_type in ('text/html', 'text/xml' ): ob = ZopePageTemplate( name, str( body ) , content_type=content_type ) elif content_type[:6]=='image/': ob=Image( name, '', body, content_type=content_type ) else: ob=File( name, '', body, content_type=content_type ) return ob
def scaleImage(self, img, width, height): """Return a scaled OFS.Image instance @param img: an OFS.Image instance. @param width: width in pixels @param height: height in pixels if img is not an Image, it is returned as is. """ if type(img) in (StringType, ) and len(img) == 0: return '' # Check image check_is_image(img) if not HAS_PIL: return img # empty string - stop rescaling because PIL fails on an empty string if img.get_size() == 0: return '' # If null size returns empty string if width == 0 or height == 0: return '' size = int(width), int(height) image = PIL.Image.open(StringIO(img.data)) # consider image mode when scaling # source images can be mode '1','L,','P','RGB(A)' # convert to greyscale or RGBA before scaling # preserve palletted mode (but not pallette) # for palletted-only image formats, e.g. GIF # PNG compression is OK for RGBA thumbnails original_mode = image.mode if original_mode == '1': image = image.convert('L') elif original_mode == 'P': image = image.convert('RGBA') image.thumbnail(size, PIL.Image.ANTIALIAS) # XXX: tweak to make the unit test # test_fields.ProcessingTest.test_processing_fieldset run format = image.format and image.format or 'GIF' # decided to only preserve palletted mode # for GIF, could also use image.format in ('GIF','PNG') if original_mode == 'P' and format == 'GIF': image = image.convert('P') thumbnail_file = StringIO() # quality parameter doesn't affect lossless formats image.save(thumbnail_file, format, quality=88) thumbnail_file.seek(0) return Image('thumb', 'thumb', thumbnail_file, content_type='image/png')
def constraint(self, image): tmpImageName = '%s.jpg_temp' % self.context.getId() tmpImage = Image(tmpImageName, tmpImageName, image) imageContentType = tmpImage.content_type if (imageContentType != 'image/jpeg'): raise VGSImageWrongType(imageContentType) return True
def __init__(self): """ Constructor. """ self.id = 'content' file = open( _fileutil.getOSPath(package_home(globals()) + '/www/spacer.gif'), 'rb') self.zmi_logo = Image(id='logo', title='', file=file.read()) file.close()
def testGetBadMembers(self): # Should list members with bad images # We should not have any bad images out of the box self.assertEqual(self.membership.getBadMembers(), []) # Let's add one bad_file = Image(id=TEST_USER_ID, title='', file=StringIO('<div>This is a lie!!!</div>')) # Manually set a bad image using private methods self.portal.portal_memberdata._setPortrait(bad_file, TEST_USER_ID) self.assertEqual(self.membership.getBadMembers(), [TEST_USER_ID]) # Try an empty image empty_file = Image(id=TEST_USER_ID, title='', file=StringIO('')) self.portal.portal_memberdata._setPortrait(empty_file, TEST_USER_ID) self.assertEqual(self.membership.getBadMembers(), []) # And a good image self.membership.changeMemberPortrait(self.makeRealImage(), TEST_USER_ID) self.assertEqual(self.membership.getBadMembers(), [])
def testBlobbableOFSImage(self): gif = getImage() obj = Image('foo', 'Foo', StringIO(gif)) obj.filename = 'foo.gif' blobbable = IBlobbable(obj) target = Blob() blobbable.feed(target) self.assertEqual(target.open('r').read(), gif) self.assertEqual(blobbable.filename(), 'foo.gif') self.assertEqual(blobbable.mimetype(), 'image/gif')
def _default_PUT_factory(self, name, typ, body): # Return DTMLDoc/PageTemplate/Image/File, based on sniffing. if name and name.endswith('.pt'): ob = ZopePageTemplate(name, body, content_type=typ) elif typ in ('text/html', 'text/xml', 'text/plain'): ob = DTMLDocument('', __name__=name) elif typ[:6] == 'image/': ob = Image(name, '', body, content_type=typ) else: ob = File(name, '', body, content_type=typ) return ob
def _changePortraitFor(self, portrait, username): """ Like getToolByName(self, 'portal_membership').changeMemberPortrait(portrait, username), that is not working anymore after the PloneHotfix20130618 """ portal_membership = getToolByName(self, 'portal_membership') safe_id = portal_membership._getSafeMemberId(username) if portrait and portrait.filename: scaled, mimetype = scale_image(portrait) portrait = Image(id=safe_id, file=scaled, title='') membertool = getToolByName(self, 'portal_memberdata') membertool._setPortrait(portrait, safe_id)
def create_users(context, users, avatars_dir): """Creates user from the given list of dictionaries. ``context`` is the step context. ``users`` is a list of dictionaries each containing the following keys: * userid * fullname * email * location * description * follows (a list of userids followed) ``avatars_dir`` is a directory where for each userid there is a ``$userid.jpg`` file. """ logger = logging.getLogger('ploneintranet.suite.create_users') for i, user in enumerate(users): email = decode(user['email']) userid = decode(user['userid']) file_name = '{}.jpg'.format(userid) properties = { 'fullname': user.get('fullname', u"Anon Ymous {}".format(i)), 'location': user.get('location', u"Unknown"), 'description': user.get('description', u"") } try: api.user.create(email=email, username=userid, password='******', properties=properties) except ValueError: user = api.user.get(username=userid) user.setMemberProperties(properties) logger.info('Created user {}'.format(userid)) portrait_filename = os.path.join(avatars_dir, file_name) portrait = context.openDataFile(portrait_filename) if portrait: scaled, mimetype = scale_image(portrait) portrait = Image(id=userid, file=scaled, title='') memberdata = api.portal.get_tool(name='portal_memberdata') memberdata._setPortrait(portrait, userid) else: logger.warning('Missing portrait file for {}: {}'.format( userid, portrait_filename)) # setup social network graph = queryUtility(INetworkGraph) graph.clear() for user in users: for followee in user.get('follows', []): graph.set_follow(userid, decode(followee))
def createFilesFromFsFolder(self, f, dir): """ Recursively put the files from a fs folder into a ZODB folder. """ filenames = os.listdir(dir) for filename in filenames: if re.match(r'(?:\..*|CVS|_darcs)', filename): continue id, type = os.path.splitext(filename) type = type.lstrip('.') this_path = os.path.join(dir, filename) if os.path.isdir(this_path): f.manage_addFolder(filename) # add folder createFilesFromFsFolder(self, f[filename], this_path) # recurse else: text = open(this_path, 'r').read() if type == 'dtml': addDTMLMethod(f, filename[:-5], title='', file=text) elif re.match(r'(?:(?:rst|stx|html|latex)(?:dtml)?|txt)', type): headers, body = parseHeadersBody(text) if headers.has_key('title'): title = headers['title'] else: title = '' if headers.has_key('parents'): parents = headers['parents'] parents = parents.split(',') else: parents = [] addZWikiPage(f, id, title=title, page_type=type, file=body, parents=parents) elif type == 'pt': f._setObject(id, ZopePageTemplate(id, text, 'text/html')) elif type == 'py': f._setObject(id, PythonScript(id)) f._getOb(id).write(text) elif type == 'zexp' or type == 'xml': connection = self.getPhysicalRoot()._p_jar f._setObject( id, connection.importFile(dir + os.sep + filename, customImporters=customImporters)) #self._getOb(id).manage_changeOwnershipType(explicit=0) elif type in ['jpg', 'jpeg', 'gif', 'png']: f._setObject(filename, Image(filename, '', text)) else: id = f._setObject(filename, File(filename, '', text)) if type == 'css': f[filename].content_type = 'text/css'
def manage_doCustomize(self, folder_path, data=None, RESPONSE=None): ''' Makes an Image with the same data. ''' custFolder = self.getCustomizableObject() fpath = tuple(split(folder_path, '/')) folder = self.restrictedTraverse(fpath) if data is None: data = self._readFile() id = self.id() obj = Image(id, '', data) folder._verifyObjectPaste(obj, validate_src=0) folder._setObject(id, obj) if RESPONSE is not None: RESPONSE.redirect('%s/%s/manage_main' % (folder.absolute_url(), id))
def test_OFSFileLastModified_Image(self): from OFS.Image import Image dummy = Image('dummy', 'Dummy', 'data') self.assertEqual(None, ILastModified(dummy)()) timestamp = 987654321.0 # time stamp (in UTC) ts = TimeStamp(*time.gmtime(timestamp)[:6]) # corresponding TimeStamp # equivalent in local time, which is what the last-modified adapter # should return mod = datetime.datetime.fromtimestamp(timestamp, tzlocal()) dummy._p_jar = FauxDataManager() dummy._p_serial = repr(ts) self.assertEqual(mod, ILastModified(dummy)())
def _default_PUT_factory(self, name, typ, body): # See if the name contains a file extension shortname, ext = os.path.splitext(name) # Make sure the body is bytes if not isinstance(body, bytes): body = body.encode('UTF-8') if ext == '.dtml': ob = DTMLDocument('', __name__=name) elif typ in ('text/html', 'text/xml'): ob = ZopePageTemplate(name, body, content_type=typ) elif typ[:6] == 'image/': ob = Image(name, '', body, content_type=typ) else: ob = File(name, '', body, content_type=typ) return ob
def add_portrait_user(user): """ Esta función le pide al max la foto de perfil del usuario la añade al portrait de plone y guarda en un soup si es la de por defecto o no """ id = user.id maxclient, settings = getUtility(IMAXClient)() foto = maxclient.people[id].avatar imageUrl = foto.uri + '/large' portrait = urllib.urlretrieve(imageUrl) scaled, mimetype = convertSquareImage(portrait[0]) portrait = Image(id=id, file=scaled, title=id) portal = api.portal.get() membertool = api.portal.get_tool(name='portal_memberdata') membertool._setPortrait(portrait, str(id)) import transaction transaction.commit() member_info = get_safe_member_by_id(id) if member_info.get('fullname', False) \ and member_info.get('fullname', False) != id \ and isinstance(portrait, Image) and portrait.size != 3566 and portrait.size != 6186: portrait_user = True # 3566 is the size of defaultUser.png I don't know how get image # title. This behavior is reproduced in profile portlet. Ahora tambien 6186 else: portrait_user = False soup_users_portrait = get_soup('users_portrait', portal) exist = [r for r in soup_users_portrait.query(Eq('id_username', id))] if exist: user_record = exist[0] user_record.attrs['id_username'] = id user_record.attrs['portrait'] = portrait_user else: record = Record() record_id = soup_users_portrait.add(record) user_record = soup_users_portrait.get(record_id) user_record.attrs['id_username'] = id user_record.attrs['portrait'] = portrait_user soup_users_portrait.reindex(records=[user_record])
def test_comment_with_author_image(self): setRoles(self.portal, TEST_USER_ID, ["Manager"]) # set member portrait membertool = getToolByName(self.portal, "portal_memberdata") membertool._setPortrait( Image(id=TEST_USER_ID, file=dummy.File(), title=""), TEST_USER_ID) self.conversation = IConversation(self.doc) self.replies = IReplies(self.conversation) comment = createObject("plone.Comment") comment.text = "Hey ho, let's go!" comment.author_username = TEST_USER_ID self.comment = self.replies[self.replies.addComment(comment)] serializer = getMultiAdapter((self.comment, self.request), ISerializeToJson) self.assertEqual( f"{self.portal_url}/portal_memberdata/portraits/test_user_1_", serializer().get("author_image"), )
def __call__(self, *args, **kw): if self.request.get('submit'): mtool = getToolByName(self.context, 'portal_membership') portrait = self.request.form.get('portrait') if (portrait and portrait.filename): portal = api.portal.get() profiles = portal.profiles profile = mtool.getAuthenticatedMember().getId() scaled, mimetype = scale_image(portrait) img = Image(id=cleanId(profile), file=scaled, title='') image = NamedBlobImage( data=str(img.data), filename=portrait.filename.decode('utf-8')) getattr(profiles, profile).portrait = image IStatusMessage(self.request).add(_( "Personal image updated. Keep browsing or reload the " "page to see the change."), type="success") # purge varnish portrait_url = mtool.getPersonalPortrait( profile).absolute_url() try: requests.request("PURGE", portrait_url, verify=False, timeout=3) except (requests.exceptions.RequestException, requests.exceptions.SSLError) as e: # Attempt to purge failed. Log and continue. logging.exception(e) redirect = self.request['HTTP_REFERER'] or \ self.context.absolute_url() self.request.RESPONSE.setHeader("X-Patterns-Redirect-Url", redirect) self.request['disable_toolbar'] = True return super(PersonalTools, self).__call__(*args, **kw)
def __call__(self, portrait, safe_id): if portrait and portrait.filename: # scaled, mimetype = scale_image(portrait, max_size=(250, 250)) scaled, mimetype = convertSquareImage(portrait) if scaled: portrait = Image(id=safe_id, file=scaled, title='') membertool = getToolByName(self.context, 'portal_memberdata') membertool._setPortrait(portrait, safe_id) # Update the user's avatar on MAX # the next line to user's that have '-' in id safe_id = safe_id.replace('--', '-') scaled.seek(0) # Upload to MAX server using restricted user credentials maxclient, settings = getUtility(IMAXClient)() maxclient.setActor(settings.max_restricted_username) maxclient.setToken(settings.max_restricted_token) try: maxclient.people[safe_id].avatar.post(upload_file=scaled) except Exception as exc: logger.error(exc.message)