Plone 4: restricting published content

2019-04-07 22:04发布

问题:

On a Plone 4.x install, can either

  1. published content be restricted to a certain user/group or
  2. private content be made to show in menus and searches for not-logged-in users ?

I have a customer who wants to be able to have content that can only be viewed by a certain user/group, but will show up in a menu or search when not logged in.

What would be the best approach for achieving this functionality?

回答1:

You'll have to customize your workflow as below:

  • go to Zope Management Interface-> portal_workflow
  • Create a new state, let's say "Trailer" (this is optional, you could customize an existing state instead...maybe the private state would be a good option for dealing with restrictions for specific users/groups)
  • Remove all permissions but "Access contents information" from the Anonymous user in that specific state
  • Push the "Update security settings" button

Done! Now all contents in the "Trailer" state will be searchable but not viewable by anonymous users.

Note: if you choose to create a new state, as I'd suggest, be sure to add all needed transitions too.

Edit:

Unfortunately I wasn't aware that in recent Plone's versions, there's a new index in the portal_catalog (allowedRolesAndUsers) that prevents the process above to work as it used to. The process above is still correct, though you'll need to override the default indexer. First create a new package with paster using the "plone" template. Then add in the main level of the package (e.g. my.package/my/package) a file called indexers.py with this:

from zope.interface import Interface
from plone.indexer.decorator import indexer
from AccessControl.PermissionRole import rolesForPermissionOn
from Products.CMFCore.utils import getToolByName
from Products.CMFCore.CatalogTool import _mergedLocalRoles

@indexer(Interface)
def allowedRolesAndUsers(obj):
    """Return a list of roles and users with View permission.

    Used by PortalCatalog to filter out items you're not allowed to see.
    """
    allowed = {}
    for r in rolesForPermissionOn('Access contents information', obj):
        allowed[r] = 1
    # shortcut roles and only index the most basic system role if the object
    # is viewable by either of those
    if 'Anonymous' in allowed:
        return ['Anonymous']
    elif 'Authenticated' in allowed:
        return ['Authenticated']
    localroles = {}
    try:
        acl_users = getToolByName(obj, 'acl_users', None)
        if acl_users is not None:
            localroles = acl_users._getAllLocalRoles(obj)
    except AttributeError:
        localroles = _mergedLocalRoles(obj)
    for user, roles in localroles.items():
        for role in roles:
            if role in allowed:
                allowed['user:' + user] = 1
    if 'Owner' in allowed:
        del allowed['Owner']
    return list(allowed.keys())

and then in the same level add a file overrides.zcml with this:

<configure xmlns="http://namespaces.zope.org/zope">

    <adapter factory=".indexers.allowedRolesAndUsers" name="allowedRolesAndUsers" />

</configure>

In the end the tree of your product should look like this:

my.package/
├── my
│   ├── __init__.py
│   └── package
│       ├── configure.zcml
│       ├── overrides.zcml
│       ├── indexers.py
│       ├── __init__.py
│       ├── profiles
│       │   └── default
│       │       └── metadata.xml
│       └── tests.py
├── README.txt
├── setup.cfg
└── setup.py

Last thing, you need to include the newly created egg in your buildout.cfg:

eggs =
        my.package

develop =
        src/my.package

Rerun buildout. That's all.