Plone / dexterity-在某个事件中,如何更改只有所有者具有查看权限的内容类型对象的所有权角色?

时间:2015-12-02 22:39:05

标签: plone zope dexterity

我尝试更改内容类型的所有者在事件订阅者(IObjectAddedEvent)中移动后更改。

对于我的示例,我将内容类型称为合同。 创建合同时,将其移入容器

我有两种类型的用户角色:Contractor和ContractManager

合同中有一个名为“承包商”的字段,这是具有承包商角色的所有用户的选择。 ContractManager也是承包商。 只有ContractManager可以更改承包商字段,否则当承包商尝试创建合同时,只会显示其名称。 此外,除非ContractManager恰好是该合同的承包商/所有者,否则ContractManager无法对其进行编辑,只需编辑一次。

我为合同创建了一个工作流程,在工作流程中,我这样做是为了只有拥有所有者角色的用户才具有查看权限。

在我用于事件订阅者的events.py文件中,我有:

@grok.subscriber(Contract, IObjectAddedEvent)
def contractAdded(obj, event):
    #generate id of container contract will be moved into when its created
    #create a container (representing a week, i.e. contracts_12_5_2015)
    #if it doesn't already exist
    #copy and paste contract into container
    moved_contract = contracts[contract_container_id][obj.id]
    changeOwnership(moved_contract, obj.contractor)


def changeOwnership(user_id, obj):
    aq_base(obj).__ac_local_roles_block__ = True
    userid = u"%s" % userid
    membership = getToolByName(obj, 'portal_membership')
    user = membership.getMemberById(userid)
    obj.changeOwnership(user)
    obj.setCreators(userid,)
    owners = [o for o in obj.users_with_local_role('Owner')]
    for owner in owners:
        roles = list(obj.get_local_roles_for_userid(owner))
        roles.remove('Owner')
        if roles:
            obj.manage_setLocalRoles(owner, roles)
        else:
            obj.manage_delLocalRoles([owner])
    roles = list(obj.get_local_roles_for_userid(userid))
    if 'Owner' not in roles:
        roles.append('Owner')
        obj.manage_setLocalRoles(userid, roles)
    obj.reindexObjectSecurity()

不幸的是,当我以ContractManager身份登录并更改承包商的身份时,我收到此错误:

Traceback (innermost last):
Module ZPublisher.Publish, line 138, in publish
Module ZPublisher.mapply, line 77, in mapply
Module ZPublisher.Publish, line 48, in call_object
Module Solgema.fullcalendar.browser.dx, line 68, in __call__
Module plone.z3cform.layout, line 50, in update
Module plone.dexterity.browser.add, line 117, in update
Module plone.z3cform.fieldsets.extensible, line 59, in update
Module plone.z3cform.patch, line 30, in GroupForm_update
Module z3c.form.group, line 145, in update
Module plone.app.z3cform.csrf, line 21, in execute
Module z3c.form.action, line 98, in execute
Module z3c.form.button, line 315, in __call__
Module z3c.form.button, line 170, in __call__
Module plone.dexterity.browser.add, line 100, in handleAdd
Module z3c.form.form, line 250, in createAndAdd
Module plone.dexterity.browser.add, line 79, in add
AttributeError: 'NoneType' object has no attribute 'id'

我假设登录用户需要reindexObjectSecurity的查看权限才能工作。当我进入工作流管理器(通过ZMI)并添加了ContractManager的查看权限时,所有者已成功更改,但在我的情况下,我尝试将其设置为只有所有者才能在导航中看到。如果是这样的话有办法解决这个问题吗?

1 个答案:

答案 0 :(得分:3)

您可以使用context manager在此操作期间更改SecurityManager。

这样,您可以将一些特定的代码行作为具有必要权限的其他用户运行。

此示例上下文管理器以系统用户身份运行代码:

import AccessControl


class SwitchedToSystemUser(object):
    """Switch temp. to System user
    """

    def __init__(self):
        self._original_security = None

    def __enter__(self):
        assert self._original_security is None

        self._original_security = AccessControl.getSecurityManager()

        _system_user = AccessControl.SecurityManagement.SpecialUsers.system
        AccessControl.SecurityManagement.newSecurityManager(None, _system_user)

    def __exit__(self, _exc_type, _exc_value, _traceback):
        AccessControl.SecurityManagement.setSecurityManager(
            self._original_security)
        self._original_security = None

使用示例:

// CODE FOR LOGGED-IN USER
...


with SwitchedToSystemUser():
    // DO STUFF AS SYSTEM USER


// MORE CODE FOR LOGGED-IN USER

您还可以查看plone.api.env,它为上下文管理员提供了一个或多个用户角色。