[Solved] Portlet modification date

hi! is there a way to find when a portlet, assigned to a page, has been modified? In a site (Plone 4), we've content added via portlet above the content and not in the content itself, for several pages. I would like to count all the pages modified in the last year but with the catalog I miss the modification on those "only portlet" pages...

I don't need perfect number, just an overall picture.

Yuri via Plone Community wrote at 2023-11-15 09:48 +0000:

hi! is there a way to find when a portlet, assigned to a page, has been modified? In a site (Plone 4), we've content added via portlet above the content and not in the content itself, for several pages. I would like to count all the pages modified in the last year but with the catalog I miss the modification on those "only portlet" pages...

I don't need perfect number, just an overall picture.

It is possible (though not easy):

Given a content object, you can use Plone functions to check
which portlets are associated with it.
For this, you must determine all portlet managers ("pm")
(via getSiteManager().getUtilitiesFor(IPortletManager))
and then use assignment_mapping_for_key(site, pm, CONTEXT_CATEGORY, path).
This gives you a mapping whose values are the portlets (their assignments)
associated with the content object identified by its site
relative path for the portlet manager pm.

A portlet assignment is a persistent object.
Its _p_serial represents a timestamp identifying its most recent
modification. You can use persistent.timestamp.TimeStamp
to convert the 8 _p_serial bytes into a object fron which
you can derive a date (e.g. via the methods timeTime, year, month,
day).

1 Like

Thanks @dieter! @petschki pointed me to _p_mtime, is it the same of _p_serial? I would like see if some static portlet assigned to the page has been modified.

This is an external method that returns the name of the portlet and the modification time:

from zope.component import getMultiAdapter, getUtility
from plone.portlets.interfaces import IPortletRetriever, IPortletManager, IPortletAssignmentMapping

def port_mod(self):

    manager = getUtility(IPortletManager, name=u"plone.rightcolumn")
    retriever = getMultiAdapter((self, manager), IPortletRetriever)
    for info in retriever.getPortlets():
        mdate = DateTime(info['assignment']._p_mtime)
        modifieds.append((mdate, info['name']))
    return modifieds

sources: https://github.com/plone/plone.portlet.static/blob/master/plone/portlet/static/static.py https://stackoverflow.com/questions/11211134/how-do-i-get-the-kind-of-portlet-group-context-type-from-its-renderer-in-pl https://4.docs.plone.org/old-reference-manuals/portlets/assignments.html

seems not to work on pages in subfolders, returns always the portlets assigned on the root of the plone site, and not the context of the script, maybe that self above is not correct. I've to dig in the external methods documentation.

Yuri via Plone Community wrote at 2023-11-15 16:39 +0000:

Thanks @dieter! @petschki pointed me to _p_mtime, is it the same of _p_serial?
It represents the same timestamp (in a different representation).

1 Like

Yuri via Plone Community wrote at 2023-11-15 16:53 +0000:

seems not to work on pages in subfolders, returns always the portlets assigned on the root of the plone site, and not the context of the script, maybe that self above is not correct. I've to dig in the external methods documentation.

retriever = getMultiAdapter((self, manager), IPortletRetriever)

Almost surely, the self in the line above controls for which
content object you get the portlets.

Being an external method, maybe the self point to the context of the script, I've to dig into it.
But:

https://zope.readthedocs.io/en/latest/zopebook/ScriptingZope.html#creating-thumbnails-from-images

"Notice that the first parameter to the above function is called self. This parameter is optional. If self is the first parameter to an External Method function definition, it will be assigned the value of the calling context (in this case, a folder). It can be used much like the context we have seen in Scripts (Python)."

https://github.com/zopefoundation/Zope/blob/master/docs/zopebook/BasicObject.rst#testing-an-external-method-object

"Astute readers will note that the 'id' provided by the output is not the 'id' of the External Method ('SalesEM'), but is instead the 'id' of the "containing" folder, which is named 'Sales'! This is a demonstration of the fact that External Methods (as well as Script (Python) objects) are mostly meant to be used in the "context" of another object, which is often a Folder."

:neutral_face:

Solved!

the problem was I applied the script to the page as default view, but the context for the script was the folder, not the page. It works as expected when applied to the page with portlets.

Thanks to all!