def scale_image_size(file_name, file_data, content_type): """ Scales an image down to at most max_size preserving aspect ratio from an input file """ # we only handle image files if not content_type.startswith("image"): return (file_name, file_data, content_type) # check if we have a ul_scale_image_size property portal = component.getUtility(ISiteRoot) sp = getToolByName(portal, "portal_properties").site_properties ul_scale_image_size = sp.getProperty('ul_scale_image_size', '') if ul_scale_image_size: # we have a property sizes = ul_scale_image_size.split(",") if len(sizes) != 2: logger.error("Wrong number of arguments given! " "Expected: 2, Got: %s" % len(sizes)) return (file_name, file_data, content_type) try: logger.info("Scaling down Image %s to a size of %s" % (file_name, sizes)) new_file, mimetype = scale_image(file_data, sizes) file_data = new_file except IOError, e: logger.error( "An error occured while trying to scale the image: %s" % str(e))
def changeMemberPortrait(self, portrait, id=None): """update the portait of a member. Modified from CMFPlone version to URL-quote the member id. """ safe_id = self._getSafeMemberId(id) if not safe_id: safe_id = self.getAuthenticatedMember().getId() membertool = getToolByName(self, 'portal_memberdata') membership = getToolByName(self, 'portal_membership') if portrait and portrait.filename: scaled, mimetype = scale_image(portrait, max_size=PORTRAIT_SIZE) image = Portrait(id=safe_id, file=scaled, title='') image.manage_permission('View', ['Authenticated', 'Manager'], acquire=False) membertool._setPortrait(image, safe_id) # Now for thumbnails portrait.seek(0) scaled, mimetype = crop_and_scale_image(portrait) image = Portrait(id=safe_id, file=scaled, title='') image.manage_permission('View', ['Authenticated', 'Manager'], acquire=False) membertool._setPortrait(image, safe_id, thumbnail=True) # Reindex memberdata = membership.getMemberById(safe_id) if memberdata is not None: memberdata.notifyModified()
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 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 scale_image_size(file_name, file_data, content_type): """ Scales an image down to at most max_size preserving aspect ratio from an input file """ # we only handle image files if not content_type.startswith("image"): return (file_name, file_data, content_type) # check if we have a ul_scale_image_size property portal = component.getUtility(ISiteRoot) sp = getToolByName(portal, "portal_properties").site_properties ul_scale_image_size = sp.getProperty('ul_scale_image_size', '') if ul_scale_image_size: # we have a property sizes = ul_scale_image_size.split(",") if len(sizes) != 2: logger.error("Wrong number of arguments given! " "Expected: 2, Got: %s" % len(sizes)) return (file_name, file_data, content_type) try: logger.info("Scaling down Image %s to a size of %s" % (file_name, sizes)) new_file, mimetype = scale_image(file_data, sizes) file_data = new_file except IOError, e: logger.error("An error occured while trying to scale the image: %s" % str(e))
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 _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 changeMemberPortrait(self, portrait, id=None): """update the portait of a member. Modified from CMFPlone version to URL-quote the member id. """ safe_id = self._getSafeMemberId(id) if not safe_id: safe_id = self.getAuthenticatedMember().getId() 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 setPortrait(self, portrait, member_id): """ store portrait for particular member. portrait must be file-like object""" if member_id in self.portraits: self.portraits._delObject(member_id) # ignore VirtualImage portraits if isinstance(portrait, VirtualImage): return False if portrait and portrait.filename: scaled, mimetype = scale_image(portrait) portrait = Image(id=safe_id, file=scaled, title='') self.portraits._setObject(id= member_id, object=portrait) return True
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 applyChanges(self, data): context = aq_inner(self.context) mtool = getToolByName(context, 'portal_membership') member = mtool.getAuthenticatedMember() member.setMemberProperties({ 'fullname': data['fullname'], 'location': data['location'], 'home_page': data['home_page'], 'organization': data['organization'], 'presslink': data['presslink']}) image_file = data['portrait'] if image_file: portrait = StringIO(image_file.data) scaled, mimetype = scale_image(portrait) portrait = Image(id=cleanId(member.getId()), file=scaled, title='') mdata = getToolByName(context, 'portal_memberdata') mdata._setPortrait(portrait, cleanId(member.getId())) IStatusMessage(self.request).addStatusMessage( _(u"Member information has been updated successfully."), type='info') return self.request.response.redirect(context.absolute_url())
def demo(context): if context.readDataFile('plonesocial.suite_demo.txt') is None: return portal = site = context.getSite() avatar_path = os.path.join(context._profile_path, 'avatars') # create users users = [] for file_name in os.listdir(avatar_path): userid = str(file_name.split('.')[0]) users.append(userid) properties = dict( fullname=" ".join([x.capitalize() for x in userid.split("_")]), location=random.choice(("New York", "Chicago", "San Francisco", "Paris", "Amsterdam", "Zurich")), description=" ".join(loremipsum.get_sentences(2))) try: api.user.create(email='*****@*****.**' % userid, username=userid, password='******', properties=properties) except ValueError: user = api.user.get(username=userid) user.setMemberProperties(properties) portrait = context.openDataFile(file_name, 'avatars') scaled, mimetype = scale_image(portrait) portrait = Image(id=userid, file=scaled, title='') memberdata = getToolByName(site, 'portal_memberdata') memberdata._setPortrait(portrait, userid) # setup social network graph = queryUtility(INetworkGraph) graph.clear() testusers = ['clare_presler', 'kurt_silvio'] graph.set_follow(testusers[1], testusers[0]) # give clare som extra followers for fan in ['christian_stoner', 'guy_hachey', 'jamie_jacko']: graph.set_follow(fan, testusers[0]) # fully random followers for i in xrange(100): followee = random.choice(users) follower = random.choice(users) if followee in testusers or follower in testusers \ or followee == follower: continue else: graph.set_follow(follower, followee) # setup publicly accessible folder and document portal.invokeFactory('Folder', 'public', title=u"Public Folder") public = portal['public'] public.invokeFactory('Document', 'd1', title=u"Public Document") # create and fill a local IMicroblogContext workspace workspace_users = [ 'clare_presler', 'dollie_nocera', 'esmeralda_claassen', 'pearlie_whitby' ] if 'workspace' not in portal: portal.invokeFactory('Folder', 'workspace', title=u"Secure Workspace") # enable local microblog directlyProvides(portal.workspace, IMicroblogContext) # in testing we don't have the 'normal' default workflow workflowTool = getToolByName(portal, 'portal_workflow') if workflowTool.getInfoFor(portal.workspace, 'review_state') != 'private': workflowTool.doActionFor(portal.workspace, 'hide') # share workspace with some users for userid in workspace_users: api.user.grant_roles(username=userid, obj=portal.workspace, roles=['Contributor', 'Reader', 'Editor']) # update object_provides + workflow state + sharing indexes portal.workspace.reindexObject() # microblog random loremipsum # prepare microblog microblog = queryUtility(IMicroblogTool) microblog.clear() # wipe all tags = ("hr", "marketing", "fail", "innovation", "learning", "easy", "newbiz", "conference", "help", "checkthisout") for i in xrange(100): # select random user userid = random.choice(users) # generate text text = " ".join(loremipsum.get_sentences(3)) if random.choice((True, False)): text += " #%s" % random.choice(tags) if userid in workspace_users: # workspace text += ' #girlspace' status = StatusUpdate(text, context=portal.workspace) else: # global status = StatusUpdate(text) status.userid = userid status.creator = " ".join([x.capitalize() for x in userid.split("_")]) # distribute most over last week if i < 90: offset_time = random.random() * 3600 * 24 * 7 status.id -= int(offset_time * 1e6) status.date = DateTime(time.time() - offset_time) microblog.add(status) # microblog deterministic test content most recent # workspace t0 = ('Workspaces can have local microblogs and activitystreams. ' 'Local activitystreams show only local status updates. ' 'Microblog updates will show globally only for users who ' 'have the right permissions. This demo has a #girlspace workspace.') s0 = StatusUpdate(t0, context=portal.workspace) s0.userid = workspace_users[0] # clare s0.creator = " ".join([x.capitalize() for x in s0.userid.split("_")]) microblog.add(s0) # global t1 = ('The "My Network" section only shows updates ' 'of people you are following.') s1 = StatusUpdate(t1) s1.userid = testusers[0] # clare s1.creator = " ".join([x.capitalize() for x in s1.userid.split("_")]) microblog.add(s1) t2 = 'The "Explore" section shows all updates of all people.' s2 = StatusUpdate(t2) s2.userid = testusers[1] # kurt s2.creator = " ".join([x.capitalize() for x in s2.userid.split("_")]) microblog.add(s2) t3 = 'The #demo hashtag demonstrates that you can filter on topic' s3 = StatusUpdate(t3) s3.userid = s2.userid # kurt s3.creator = s2.creator microblog.add(s3) # commit microblog.flush_queue() transaction.commit()
def demo(context): if context.readDataFile('plonesocial.suite_demo.txt') is None: return portal = site = context.getSite() avatar_path = os.path.join(context._profile_path, 'avatars') # create users users = [] for file_name in os.listdir(avatar_path): userid = str(file_name.split('.')[0]) users.append(userid) properties = dict( fullname=" ".join([x.capitalize() for x in userid.split("_")]), location=random.choice( ("New York", "Chicago", "San Francisco", "Paris", "Amsterdam", "Zurich")), description=" ".join(loremipsum.get_sentences(2))) try: api.user.create(email='*****@*****.**' % userid, username=userid, password='******', properties=properties) except ValueError: user = api.user.get(username=userid) user.setMemberProperties(properties) portrait = context.openDataFile(file_name, 'avatars') scaled, mimetype = scale_image(portrait) portrait = Image(id=userid, file=scaled, title='') memberdata = getToolByName(site, 'portal_memberdata') memberdata._setPortrait(portrait, userid) # setup social network graph = queryUtility(INetworkGraph) graph.clear() testusers = ['clare_presler', 'kurt_silvio'] graph.set_follow(testusers[1], testusers[0]) # give clare som extra followers for fan in ['christian_stoner', 'guy_hachey', 'jamie_jacko']: graph.set_follow(fan, testusers[0]) # fully random followers for i in xrange(100): followee = random.choice(users) follower = random.choice(users) if followee in testusers or follower in testusers \ or followee == follower: continue else: graph.set_follow(follower, followee) # setup publicly accessible folder and document portal.invokeFactory('Folder', 'public', title=u"Public Folder") public = portal['public'] public.invokeFactory('Document', 'd1', title=u"Public Document") # create and fill a local IMicroblogContext workspace workspace_users = ['clare_presler', 'dollie_nocera', 'esmeralda_claassen', 'pearlie_whitby'] if 'workspace' not in portal: portal.invokeFactory('Folder', 'workspace', title=u"Secure Workspace") # enable local microblog directlyProvides(portal.workspace, IMicroblogContext) # in testing we don't have the 'normal' default workflow workflowTool = getToolByName(portal, 'portal_workflow') if workflowTool.getInfoFor(portal.workspace, 'review_state') != 'private': workflowTool.doActionFor(portal.workspace, 'hide') # share workspace with some users for userid in workspace_users: api.user.grant_roles(username=userid, obj=portal.workspace, roles=['Contributor', 'Reader', 'Editor']) # update object_provides + workflow state + sharing indexes portal.workspace.reindexObject() # microblog random loremipsum # prepare microblog microblog = queryUtility(IMicroblogTool) microblog.clear() # wipe all tags = ("hr", "marketing", "fail", "innovation", "learning", "easy", "newbiz", "conference", "help", "checkthisout") for i in xrange(100): # select random user userid = random.choice(users) # generate text text = " ".join(loremipsum.get_sentences(3)) if random.choice((True, False)): text += " #%s" % random.choice(tags) if userid in workspace_users: # workspace status = StatusUpdate(text, context=portal.workspace, tags=['girlspace']) else: # global status = StatusUpdate(text) status.userid = userid status.creator = " ".join([x.capitalize() for x in userid.split("_")]) # distribute most over last week if i < 90: offset_time = random.random() * 3600 * 24 * 7 status.id -= int(offset_time * 1e6) status.date = DateTime(time.time() - offset_time) microblog.add(status) # microblog deterministic test content most recent # workspace t0 = ('Workspaces can have local microblogs and activitystreams. ' 'Local activitystreams show only local status updates. ' 'Microblog updates will show globally only for users who ' 'have the right permissions. This demo has a #girlspace workspace.') s0 = StatusUpdate(t0, context=portal.workspace, tags=['girlspace']) s0.userid = workspace_users[0] # clare s0.creator = " ".join([x.capitalize() for x in s0.userid.split("_")]) microblog.add(s0) # global t1 = ('The "My Network" section only shows updates ' 'of people you are following.') s1 = StatusUpdate(t1) s1.userid = testusers[0] # clare s1.creator = " ".join([x.capitalize() for x in s1.userid.split("_")]) microblog.add(s1) t2 = 'The "Explore" section shows all updates of all people.' s2 = StatusUpdate(t2) s2.userid = testusers[1] # kurt s2.creator = " ".join([x.capitalize() for x in s2.userid.split("_")]) microblog.add(s2) t3 = 'The #demo hashtag demonstrates that you can filter on topic' s3 = StatusUpdate(t3, tags=['demo']) s3.userid = s2.userid # kurt s3.creator = s2.creator microblog.add(s3) # commit microblog.flush_queue() transaction.commit()
def __call__(self, portrait, safe_id): if portrait and portrait.filename: scaled, mimetype = scale_image(portrait) portrait = Image(id=safe_id, file=scaled, title='') membertool = getToolByName(self.context, 'portal_memberdata') membertool._setPortrait(portrait, safe_id)
def __call__(self, portrait, safe_id): if portrait and portrait.filename: scaled, mimetype = scale_image(portrait) portrait = Image(id=safe_id, file=scaled, title='') membertool = api.portal.get_tool(name='portal_memberdata') membertool._setPortrait(portrait, safe_id)
def demo(context): if context.readDataFile('plonesocial.suite_demo.txt') is None: return site = context.getSite() avatar_path = os.path.join(context._profile_path, 'avatars') # create users users = [] for file_name in os.listdir(avatar_path): userid = str(file_name.split('.')[0]) users.append(userid) properties = dict( fullname=" ".join([x.capitalize() for x in userid.split("_")]), location=random.choice( ("New York", "Chicago", "San Francisco", "Paris", "Amsterdam", "Zurich")), description=" ".join(loremipsum.get_sentences(2))) try: api.user.create(email='*****@*****.**' % userid, username=userid, password='******', properties=properties) except ValueError: user = api.user.get(username=userid) user.setMemberProperties(properties) portrait = context.openDataFile(file_name, 'avatars') scaled, mimetype = scale_image(portrait) portrait = Image(id=userid, file=scaled, title='') memberdata = getToolByName(site, 'portal_memberdata') memberdata._setPortrait(portrait, userid) # setup social network graph = queryUtility(INetworkGraph) graph.clear() for i in xrange(100): followee = random.choice(users) follower = random.choice(users) if followee != follower: graph.set_follow(follower, followee) # microblog microblog = queryUtility(IMicroblogTool) microblog.clear() # wipe all tags = ("hr", "marketing", "fail", "innovation", "learning", "easy", "newbiz", "conference", "help", "checkthisout") for i in xrange(100): text = " ".join(loremipsum.get_sentences(3)) if random.choice((True, False)): text += " #%s" % random.choice(tags) status = StatusUpdate(text) # assign to random user userid = random.choice(users) status.userid = userid status.creator = " ".join([x.capitalize() for x in userid.split("_")]) # distribute most over last week if i < 90: offset_time = random.random() * 3600 * 24 * 7 status.id -= int(offset_time * 1e6) status.date = DateTime(time.time() - offset_time) microblog.add(status) microblog.flush_queue()