Adattare dinamicamente la vista degli utenti: un esempio della potenza degli adattatori in Plone applicato ad un caso reale
medio
Questa guida mostrerà come possiamo già da ora beneficiare della flessibilità e potenza della Zope Component Architecture (ZCA), prendendo come spunto un semplice esempio pratico. Lo stesso modo di procedere può essere utilizzato per customizzare la costruzione delle sitemap, strategie per la navigazione, ecc.
Supponiamo di dover implementare in Plone un sistema per la gestione di aree ad accesso riservato, e di dover filtrare dalla vista dei permessi locali alcuni oggetti degli utenti, secondo alcuni criteri (magari in base al contesto).
Si può fare in maniera elegante, generica, facilmente mantenibile nel tempo e con poche righe di codice, senza modificare direttamente il codice originale!
Prerequisiti
- Plone 3
Passo passo
Dove viene costruita la lista dei Member?
Se dobbiamo filtrare la lista degli utenti del portale per prima cosa dobbiamo scoprire DOVE e COME viene costruita la lista degli utenti.
La lista degli utenti viene costruita istanziando il multiadapter pas_search, il quale espone una serie di metodi (fare riferimento a Products.PlonePAS.interfaces.browser.IPASSearchView per ulteriori informazioni), tra cui anche searchUsers.
Nel nostro caso dovremo adattare alle nostre esigenze proprio il metodo searchUsers, richiamato dalle viste che si occupano di gestire i local roles sui singoli oggetti o per la gestione degli utenti.
Ecco come viene richiamato nel codice originale di Plone il multiadapter per fare le query sugli utenti (plone/app/workflow/browser/sharing.py):
...
hunter = getMultiAdapter((context, self.request), name='pas_search')
for userinfo in hunter.searchUsers(fullname=search_term):
userid = userinfo['userid']
... Da notare: le nostre modifiche NON impattano sul codice di Plone!
Adattiamo alle nostre esigenze la query degli utenti
Quello che dobbiamo fare è scrivere una nuova classe che estenda quella chiamata Products.PlonePAS.browser.search import PASSearchView e che faccia l'overloading del solo metodo searchUsers, aggiungendo le logiche per il filtraggio degli utenti che vogliamo implementare.
browser/search.py:
from zope.interface import implements
from Products.PlonePAS.interfaces.browser import IPASSearchView
from Products.PlonePAS.browser.search import PASSearchView as PASDefaultSearchView
from Products.CMFPlone.interfaces import IPloneSiteRoot
from redomino.workgroup.interfaces import IWorkgroup
from redomino.workgrouptool.content.workgroup_tool import WORKGROUP_MEMBERDATA
class PASSearchView(PASDefaultSearchView):
implements(IPASSearchView)
def searchUsers(self, sort_by=None, **criteria):
# chiamo il metodo searchUsers della classe originale
results = PASDefaultSearchView.searchUsers(self, sort_by, **criteria)
# results è un dizionario python
if IPloneSiteRoot.providedBy(self.context):
# per il plone site, tutti i risultati NON filtrati
return results
elif IWorkgroup.providedBy(self.context):
# solo i risultati relativi al workgroup su cui mi trovo, piu'gli utenti globali
return filter(lambda x: condizione1 su x, results)
else:
# in tutti gli altri contesti, filtro via TUTTI gli elementi non globali
return filter(lambda x: condizione2 su x, results)
return results Registriamo il nostro adapter per tutte le interfacce (browser/overrides.zcml):
<configure xmlns="http://namespaces.zope.org/zope" xmlns:browser="http://namespaces.zope.org/browser" i18n_domain="redomino.workgroup"> <!-- overrides --> <browser:page for="*" name="pas_search" class=".search.PASSearchView" permission="zope2.View" allowed_interface="Products.PlonePAS.interfaces.browser.IPASSearchView" /> </configure>
Registrazione dell'override
Facciamo l'override del nostro zcml per evitare errori al riavvio del nostro Zope (buildout.cfg), supponendo di lavorare su un proprio buildout:
...
zcml =
...
redomino.workgroup.browser-overrides
... ALTERNATIVA AL PASSO PRECEDENTE: l'override in questo caso riguarderà tutti i portali Plone della nostra istanza; alternativamente, è possibile seguire la strada seguente: customizzazione utilizzando plone.browserlayer.
Da questo momento in poi verrà chiamato il NOSTRO adapter per ricercare gli utenti!
Ulteriori informazioni
Per ulteriori approfondimenti fare riferimento direttamente al codice sorgente di Plone.