Modifying read permissions on DublinCore metadata and Plone 4 - plone

I have created a custom content-type using Dexterity that works fine. This content should be viewable but its creator kept hidden from unpriviledged members.
I can obviously accomplish this by removing the document-byline from the template, but if I append, as a normal member, '/Creator' to the content I can still see the creator.
I can solve this by overriding Products.CMFDefault.DublinCore.DefaultDublinCoreImpl.Creator() and introducing an additional check, of course, but it's dirty and unmaintainable.
What's the best approach to selectively hide content DublinCore metadata from unpriviledged users, in the context of Dexterity (if applicable)?

Another solution is to redefine Zope security for this context:
import Globals
from AccessControl import ClassSecurityInfo
from Products.CMFDefault.permissions import ManagePortal
from plone.directives.dexterity import Item
Item.security = ClassSecurityInfo()
Item.security.declareProtected(ManagePortal, 'Creator')
Globals.InitializeClass(Item)
This redefines security for the 'Creator' method of dexterity.Item so
that only users with the ManagePortal permission can access this
information.
However, ajung notes that this might break any code that makes assumptions about the Creator method and doesn't find it, not having the required permission. It also removes all the previous security declarations for this method.
Any other ideas?

Related

NullPtr exception while getting country names and country codes in backoffice

After upgrading to Intershop CM 7.10.18.1, we are getting NullPtr exceptions while opening store detail page in backoffice.
ISML template for store details is EditStore_52.isml, which includes ISCountrySelectBox module, which futhermore calls getCountryNamesAndCodes() method.
That method fails with NullPtr exception because of underlined call which returns null.
We are wondering whether this is a bug and whether the intended code was supposed to be:
countriesMap.put(country.getId(), country.getDisplayName(currentLocale));
Please advise on workaround for this situation.
The following is a stack trace for exception.
Intershop delivers address data which can be imported/export through Operations backoffice (e.g. Login at https://localhost:8443/INTERSHOP/web/WFS/SLDSystem using Organization Operations). Out of the box such address data looks like this:
<country>
<id>DE</id>
<custom-attributes>
<custom-attribute dt:dt="string" name="displayName" xml:lang="de-DE">Deutschland</custom-attribute>
<custom-attribute dt:dt="string" name="displayName" xml:lang="fr-FR">Allemagne</custom-attribute>
<custom-attribute dt:dt="string" name="displayName" xml:lang="en-US">Germany</custom-attribute>
</custom-attributes>
</country>
As you can see, it only contains displayName attribute values for de-DE, fr-FR and en-US. A possible workaround in your case would be to export data, include missing attribute values and import it again.
Please note: The work to deliver a fix for this is already in progress. I'm sorry for the inconvenience.
The more convenient way (because editing xml import files is tedious) would be to replace the erroneous implementation using guice module override. In a nutshell:
Copy paste the original implementation of class com.intershop.component.region.internal.geoobject.LocalizedCountryNamesProviderImpl into a class of your own in your custom cartridge. For example: I just created a class AppSFLocalizedCountryNamesProviderImpl in cartridge app_sf_responsive to test this.
Adapt above method according to your needs
Create an override module (See Cookbook - Dependency Injection and ObjectGraphs). Following my example the modules configure operation should look like this:
#Override
protected void configure()
{
bind(LocalizedCountryNamesProvider.class).to(AppSFLocalizedCountryNamesProviderImpl.class);
bindProvider(com.intershop.component.foundation.capi.localization.LocalizedCountryNamesProvider.class)
.to(AppSFLocalizedCountryNamesProviderImpl.class);
}
Publish your cartridge, Restart your server

symfony dynamically add translation based on condition

I'm searching for a way to add a translation to an existing translation catalogue during runtime.
I have a working symfony 2.3 application which uses translations in de/en/fr/it and fetches all available translation keys from /Resources/translations/messages..yml.
Now if a user logs in I want to have the possibility to override some of the already loaded labels based on setting for that user (e.g. textfield in DB which holds key-value-pairs).
E.g.
messages.en.yml
company.name.short: Company profile
Usersetting:
company.name.short: Profile for company
I found no way to add/override keys to the existing catalogue or to make them available in twig. Is there a Bundle or a setting or some Symfony magic to get this to work?
You'll probably want to extend Symfony's own translation class for this. This article explains how to do that:
http://www.webtipblog.com/extend-symfony-2-translator-to-log-untranslated-messages-to-a-database/
The key point is to override the "translator.class" parameter in your config, and then point it to your own class that first checks for database overrules and will defer to the symfony default implementation if it cannot find one.

Listing expired plone contents only in specific contexts (folders or collections)

I've to list, in specific folders or collections, objects expired also to anonymous users.
You know, portal_catalog returns only brains not expired. It's a useful behavior but not in this case...
To force the Catalog to return also expired contents, we've to pass a specific parameter: show_inactive.
Browsing the folder_listing (&family) code I noticed that it's possible to pass, via request, optionals parameters (contentFilter) to the query/getFolderContents. It's a nice feature to customize the query avoiding the creation of very similar listing templates.
I suppose it's necessary to create a marker interface to mark context (folders or collection) where I want to list also expired contents. For ex. IListExpired.
I imagine to ways:
1) to make a subscriber that intercepts before_traverse and , in the handler, a test to verify if the context implements the IListExpired. In positive case I made a
request.set('folderListing', {'show_inactive':True})
2) to make a viewlet for the IListExpired that in the call set
request.set('folderListing', {'show_inactive':True})
What's the best way? I suppose the first one could be an unnecessary overhead.
Vito
AFAIK, these are two separate thing: folderListing uses a method available to all CMF-based Folderish content types; show_inactive is an option of the Plone catalog, so you're not going to make it work as you're planning.
I think you should override these views and rewrite the listing using a catalog call.
you better use a browser layer for you package to do so or, a marker interface as you're planning.

plone:portlet vs plone:portletRenderer (subclassing problem)

A oddity we tripped across when upgrading sites from Plone 3 to Plone 4:
We define a number of custom portlets. One of these is a "Jobs" portlet which is a lightly customised News Portlet. This was subclassed from the News portlet, as suggested by:
http://plone.org/documentation/manual/developer-manual/portlets/appendix-practicals/subclassing-new-portlets.
That is:
<plone:portlet
name="falcon.JobsPortlet"
interface=".portlets.IFalconJobsPortlet"
...
renderer=".portlets.FalconJobsRenderer"
/>
where IFalconJobsPortlet subclasses from INewsPortlet:
from plone.app.portlets.portlets.news import INewsPortlet
class IFalconJobsPortlet(INewsPortlet):
"""Interface for Jobs portlet uses the same schema as News Portlet"""
We also (separately) want to replace the render class on the standard INewsPortlet, in
order to provide a custom template:
<plone:portletRenderer
portlet="plone.app.portlets.portlets.news.INewsPortlet"
class=".portlets.FalconNewsRenderer"
layer=".interfaces.IThemeSpecific"
/>
This works fine in Plone 3. This might just have been blind luck, or it
might be case that <plone:portletRenderer> used to run before
<plone:portlet>, and now run afterwards.
In Plone 4, falcon.JobsPortlet is set up correctly, but then <plone:portletRenderer>
kicks in and replaces the renderer clause, so that
".portlets.FalconJobsRenderer" (correct) is replaced with
".portlets.FalconNewsRenderer" (incorrect)
A solution/workaround in this case was simple: I stopped subclassing from
INewsPortlet, and just copied the schema across by hand from the original superclass:
class IFalconJobsPortlet(IPortletDataProvider):
"""Interface for Jobs portlet uses the same schema as News Portlet"""
count = ...
state = ...
My question, for future reference:
Is there a way to safely combine <plone:portlet> and
<plone:portletRenderer> when subclassed portlets are in play?
If you're not using layer="..." in your <plone:portlet name="falcon.JobsPortlet"...> registration, then this is probably the root. The ZCA, which this ZCML uses to register adapters, gives one lookup precedence over another based on interface specificity. So I'm guessing the since you give a layer in your <plone:portletRenderer> but not in your <plone:portlet> then the renderer in <plone:portletRenderer> matches the portlet interface of both and the layer is more specific and so it wins.
Since only <plone:portletRenderer> supports the layer specification, I would just add a <plone:portletRenderer> registration for the FalconJobsRenderer that is registered for the same layer and that will assure correct precedence. That way you can revert your workaround and subclass INewsPortlet. It is much more appropriate to subclass INewsPortlet.

GenericSetup: What does toolset.xml accomplish if ToolInit still has to be called from initialize()

It seems that toolset.xml goes only half way. Ideally it should be able to do away with the ToolInit call in initialize() in __init__.py. But I could not get the tool icon to show in the ZMI without the ToolInit call.
The ToolInit call in the initialize function registers the tool class as something that can be added to OFS based folders in the database - primarily it register a factory for creating instances of the class. This is basically the same that ContentInit does for normal content classes.
Once the class is registered and its meta_type is known, instances of the class can be added to OFS based Folders. GenericSetup steps are responsible for managing persistent content and can be used to add tool instances to the database.
If we wanted to avoid the code in the initialize function, we would need to create some custom ZCML directives instead and use these in a configure.zcml to register the type and its factory. Dexterity has gone this route, but its not available for Archetypes based content types or general classes like tools.
The goal of toolset.xml is to instantiate tools into the database. It can also be used to remove tools; this is very useful in upgrade steps for example.
Example toolset.xml:
<?xml version="1.0"?>
<tool-setup>
<required tool_id="portal_foo" class="dotted.path.to.FooTool" />
<forbidden tool_id="portal_spam" />
</tool-setup>
This example toolset.xml would instantiate the FooTool class as portal_foo in it's context, and remove any object with id portal_spam if present.
Note that you can use a toolset.xml in any GenericSetup profile, not just in the package that defines the tool in the first place, for example, in general policy packages for a site you develop.

Resources