Ticket #12870 (confirmed PLIP)

Opened 4 years ago

Last modified 4 months ago

PLIP: Handle Portraits using PAS and PropertySheets only

Reported by: jensens Owned by:
Priority: minor Milestone: Future
Component: Backend (Python) Version:
Keywords: pas, portrait, user, property, ldap, sql, gravatar Cc: jens@…

Description

Proposer: Jens Klein

Seconder: not yet

Motivation

Plone handles user properties with PAS - except portraits. Now any pas-plugin providing portrait images need to monkey patch Products.PlonePAS. Prominent examples are Products.Remember or SQL/LDAP plugins.

The root of the problem: Plone stores portraits in portal_memberdata in a BTree and uses its API (and at some part portal_membership) everywhere portraits are involved. It is in no way connected to the usual MutablePropertySheet.

Assumptions

Also methods of MembershipTool and MemberdataTool starting with an underscore may be used outside of this class and can not be considered private.

Proposal & Implementation

Proposal:

  • in future all portrait images are read (and stored) on (from) PropertySheets.
  • by default portrait images are stored as NamedBLobImage on the normal MutablePropertysheet.
  • images not located in ZODB (ldap, sql, ...) can be exposed too.
  • images not delivered by Zope (i.e. Gravatar) can be used too (implemenatation out of plip scope)
  • new clean API is introduced (utility) handling all tasks around portrait images.
  • current API on MembershipTool and MemberdataTool is kept but code replaced to use the new API, old API gets deprecated.
  • adapters on PropertySheet are responsible for sheet specific implemenations.
  • add migration functionality

Implementation:

Products.PlonePAS.sheet.MutablePropertySheet mutable_properties gets a new default property portrait. The name of the portrait property is not customizable to avoid confusion. The property is expected to implement plone.namedfile.interfaces.INamedImage using the implemenation plone.namedfile.file.NamedBlobImage.

Introduce view @@portrait_image providing new interface IPortraitView. This view acts similar to plone.namedfile.scaling.ImageScaling but works with/is bound to the sheets IPortraitPropertyPlugin. Parts can be recycled (possibly inherited).

A new Portrait API is provided as a utility IPortraitUtility The utility is fetched and used as sketched below::

    >>> from Products.PlonePAS.utils import get_portrait_utility
    >>> portrait_util = get_portrait_utility

    >>> portrait_util.set(userid, image)
    >>> portrait_util.delete(userid)
    >>> portrait_util.get(userid)
    <Some_INamedFile_implemenation at ...>

    >>> portrait_util.get(nonexistentuserid)
    <DefaultPortrait_INamedFile_implemenation at ...>
 
    >>> portrait_util.url(userid)
    'http://localhost:8080/Plone/acl_users/@@portrait_image/userid'

    >>> portrait_util.url(userid, scale='mini')
    'http://localhost:8080/Plone/acl_users/@@portrait_image/userid/mini'

    >>> portrait_util.tag(userid)
    '<img src="http://localhost:8080/Plone/acl_users/@@portrait_image/userid" />'

    >>> portrait_util.tag(userid)
    '<img src="http://localhost:8080/Plone/acl_users/@@portrait_image/userid" />'

    >>> portrait_util.tag(userid, scale='mini')
    '<img src="http://localhost:8080/Plone/acl_users/@@portrait_image/userid/mini" />'

Utility has a helper method to get the first propertysheet with a property portrait. This can be restricted to return the first writable propertysheet (in case of get/delete).

Introducing a new Interface IPortraitPropertyHandler which provides methods convert_for_storage(nameimagedata), convert_from_storage(otherdata) and url(data). Thus also raw data (from ldap, sql, ...) can be converted to some INamedImage implemenation and vice versa. In case of externally delivered images relevant information can be returned.

In case of utilities get the first sheet with portrait property is fetched. Sheet is adapted by IImagePropertyHandler and convert_from_storage(data) is called. If data was empty the default portrait is used.

In case of set some INamedImage implemenation is expected as input. First writable sheet with portrait property is fetched. IImagePropertyHandler is adapted to the plugin. convert_for_storage(data) is called.

In case of delete an empty value is set.

In case of tag and url the first sheet with portrait property is fetched. Sheet is adapted by IImagePropertyHandler and url(data) is called. In case of tag a tag is build around the url.

By default PlonePAS provide two types of IPortraitHandler-adpaters:

  • One for propertysheets such as the default Products.PlonePAS.sheet.MutablePropertySheet enabled to read and store plone.namedfile.interfaces.INamedBlobImage.
  • Another enabled to store raw image data only, such as ldap or sql integrations. Plugins-authors may use this or built upon it for more special cases.

On MembershipTool the following methods are modified to use the new portrait API:

  • deletePersonalPortrait
  • changeMemberPortrait
  • getPersonalPortrait
  • default_portrait property on module and class, slighly different!?, both unused, we can remove this one.
  • getBadMembers - get rid of this one
  • manage_portrait_fix (property - dtml using getBadMembers)

On MemberdataTool the following methods are modified to use the new portrait API:

  • portraits (property, at the moment a BTreeFolder)
  • _getPortrait
  • _setPortrait
  • _deletePortrait
  • pruneMemberDataContents

Not part of this implementation, but an important use-case: Support of externally delivered images, i.e. Gravatar. In case of external hosted (usally non-mutable) images the provided api works too. For Gravatar portrait contains the reference i.e. E-Mail adress connected to Gravatar. The tag renderer of the utility needs renders a tag to the external image. Theres no need to get, set or delete an Gravatar image through the Plone.

Risks

  • Currently existing plugins may patch methods of MembershipTool and MemberdataTool. Such plugins probably break, but OTOH proposed change simplifies those plugins and is made for them.
  • if there is in a customized plone already a property portrait for whatever reason, it may result in data loss or weird behaviour.
  • on sites with lots of users there are lots of portraits to migrate.

Participants

Who is signed up to do the work?

  • Jens W. Klein

Progress

  • sketched first implemenation in a customer project
  • lessons learned, new ideas discussion on plone-dev ist
  • plip written
  • plip discussion open

Change History

comment:1 Changed 4 years ago by jensens

  • Type changed from Bug to PLIP
  • Milestone changed from 4.x to 4.3

comment:2 Changed 4 years ago by eleddy

  • Status changed from new to confirmed
  • Component changed from Unknown to Backend (Python)

comment:3 Changed 4 years ago by eleddy

  • Milestone changed from 4.3 to 4.4

comment:4 Changed 4 years ago by eleddy

this is a model PLIP - thanks! We are looking to be ready for 4.3 reviews by May 30th and have things merged by June 11th. Do you think you could make that deadline or do you want to shoot for 4.4?

comment:5 Changed 4 years ago by eleddy

hey jens - we are looking to have all plip implementations done by June 30th for review by june 11. Do you think you are going to make this deadline or should we look at 4.4?

comment:6 Changed 4 years ago by jensens

may is usally a very busy month here. customer wins over community at this point. this will go as a july/august project for me. it will go into 4.4 then i think.

comment:7 Changed 4 years ago by eleddy

Hey jens - how are things looking on this?

comment:8 Changed 4 years ago by gyst

Hi Jens, just a short ping to let you know I would be really happy if this PLIP got integrated. Apart from the Gravatar use case, also the fact that you'll be exposing customizable portrait scaling properties (instead of the currently hardcoded 100x75px) will be very nice.

comment:9 Changed 3 years ago by davisagli

  • Cc jens@… added
  • Version 4.2 deleted
  • Milestone changed from 4.4 to 4.x

Any interest in finishing this up for the next release of Plone?

comment:10 Changed 3 years ago by jensens

sorry for all the delay, i'am really totally overloaded. if someone like to assist i will help and also do work, but i really do not have the time time to implement this one alone. anyone?

comment:11 Changed 3 years ago by thet

For reference, here are some addons concerning external portrait handling, which might be useful for this PLIP implementation:

comment:12 Changed 3 years ago by MatthewWilkes

I'm going to put this on the potential ideas list for Summer of Code.

comment:13 Changed 3 years ago by esteele

  • Milestone changed from 4.x to 5.0

The Framework Team has decided to move on to Plone 5. Updating milestones accordingly.

comment:14 Changed 2 years ago by davisagli

  • Milestone changed from 5.0 to Future

Moving this to Future since no one is working on it at the moment.

Note: See TracTickets for help on using tickets.