2015-12-02 5 views
2

J'essaye de changer le propriétaire d'un type de contenu pour le changer après qu'il ait été déplacé dans un abonné d'événement (IObjectAddedEvent).Plone/dextérité- Dans un événement, comment puis-je modifier le rôle de propriété d'un objet de type de contenu pour lequel seul un propriétaire a l'autorisation d'afficher?

Pour mon exemple, je ferai référence au type de contenu en tant que contrat. Lorsqu'un contrat est créé, son déplacé dans un récipient

Il existe deux types de rôles utilisateur Je: Entrepreneur et ContractManager

Il y a un champ dans un contrat appelé « entrepreneur », qui est un choix pour tous les utilisateurs ayant le rôle d'entrepreneur. Un ContractManager est également un entrepreneur. Seul un ContractManager peut modifier le champ de l'entrepreneur, sinon, lorsqu'un entrepreneur tente de créer un contrat, seul son nom apparaîtra. De plus, le ContractManager ne peut pas le modifier une fois, il a été créé, à moins que le ContractManager ne soit l'Entrepreneur/Propriétaire de ce Contrat.

J'ai créé un flux de travail pour le contrat et dans le flux de travail, afin que seuls les utilisateurs ayant le rôle de propriétaire disposent de l'autorisation d'affichage.

Dans mon fichier events.py que j'utilise pour les abonnés de l'événement, j'ai ceci:

@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() 

Malheureusement, quand je suis connecté en tant ContractManager et changer qui l'entrepreneur est, je reçois cette erreur:

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' 

Je suppose que l'utilisateur connecté a besoin de l'autorisation pour du reindexObjectSecurity de travailler. Quand je suis entré dans le gestionnaire de flux de travail (via ZMI) et ajouté l'autorisation de vue pour le ContractManager, le propriétaire a changé, mais dans mon cas, j'essaie de faire en sorte que seul le propriétaire puisse voir dans le Navigation. Si c'est le cas, y a-t-il un moyen de faire passer ce problème?

Répondre

3

Vous pouvez modifier SecurityManager pendant cette action en utilisant un context manager. De cette façon, vous pouvez exécuter certaines lignes de code spécifiques en tant qu'utilisateur différent disposant des autorisations nécessaires.

Cet exemple gestionnaire de contexte exécute le code en tant qu'utilisateur du système:

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 

Exemple d'utilisation:

// CODE FOR LOGGED-IN USER 
... 


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


// MORE CODE FOR LOGGED-IN USER 

Vous pouvez également vérifier plone.api.env, qui fournit aux gestionnaires de contexte à adopter un utilisateur ou les rôles.

+0

Merci pour votre réponse. J'ai essayé d'utiliser le fichier api.env dans la fonction changeOwnserhip, mais il semble toujours être bloqué. avec api.env.adopt_user (nom d'utilisateur = user_id): propriété de #Changez, changer les rôles locaux obj.reindexObjectSecurity() J'ai ajouté une déclaration d'impression après avoir ré-indexation de la sécurité pour voir si elle est adoptée et que cela ne , mais je reçois toujours la même erreur que si AddEvent ne se termine pas à moins que l'utilisateur connecté soit le propriétaire, comme l'objet n'est pas réellement ajouté jusqu'à ce que cet événement se termine.C'est presque comme si j'avais besoin d'un événement qui se produit après AddEvent est terminé? –

+1

Pouvez-vous mettre le code que vous avez essayé quelque part (y compris adopter_role/adopt_user?) – Mathias

+0

Toute progression? Si c'est un problème de sécurité, il sera résolu en utilisant le bon gestionnaire de sécurité au bon endroit. .. et nous avons besoin de plus de code – Mathias