Meilleur auteur de réponses
Associer un event handler à une liste par code

Question
-
Bonjour,
J'ai développé un event handler qui permet de récupérer la valeur d'un champ d'une ListItem, puis redéfinir les droits sur cet item selon la valeur du champ.
voilà le code que j'ai écrit, j'aimerai bien que vous me donnez votre avis :
public override void ItemAdded(SPItemEventProperties properties) { base.ItemAdded(properties); try { SPWeb web = new SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl); SPListItem item = web.Lists[properties.ListId].GetItemById(properties.ListItemId); // première étape, casser l'héritage des droits item.BreakRoleInheritance(false); // seconde étape, assigner les nouveaux droits SPFieldUserValue userValue = new SPFieldUserValue( item.Web, item["Lecteurs"] as string); SPUser user = userValue.User; //on ajoute le user sur le dossier SPRoleDefinition roleDef = web.RoleDefinitions.GetByType(SPRoleType.Reader); SPRoleAssignment roleAssignement = new SPRoleAssignment(user); roleAssignement.RoleDefinitionBindings.Add(roleDef); item.RoleAssignments.Add(roleAssignement); } catch (Exception ex) { properties.Cancel = true; properties.ErrorMessage = "Erreur dans l'Event ItemUpdated : " + ex.Message; }
}J'ai signé la DLL et j'ai essayé par la suite de déployer ce eventhandler, j'ai ajouté un fichier .bat à mon projet mais il me
semble qu'il ne marche pas bien :
"%C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\gacutil.exe" -uf DemoEventHandler
"%C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\gacutil.exe" -if bin\Debug\DemoEventHandler.dll
iisreset
Ensuite, j'ai voulu attacher l'évènement à une liste par code mais il y a toujours des erreurs :
string AssemblySignature = "TestHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d257055f-5bf8-43d4-97a3-b071cc3db179"; string ClassName = "Class1"; objSPWeb.Lists["List Droit"].EventReceivers.Add(SPEventReceiverType.ItemAdded, AssemblySignature, ClassName);
Pouvez m'aider svp à faire ces démarches ?
Réponses
-
Bonjour,
je viens d'essayer votre code, et chez moi il a fonctionné. C'est plutôt encourageant :)
Pour débusquer le problème, vous pouvez commencer par, avec le compte admin, cliquer sur le menu contextuel de l'élément puis sur View Permissions, cela permettrait de vérifier que les autorisations on bien été redéfinies. Vous devriez y trouver les autorisations que vous avez défini par code avec votre event receiver.
Vérifiez aussi que votre code s'execute entierement, en mettant un point d'arret dans votre méthode et en vous attachant avec visual studio aux processus w3wp.exe.
Les erreurs dans les event receivers asynchrones ne sont pas remontées à l'utilisateur, donc difficile de savoir si le traitement s'est correctement terminé. Le meilleur moyen d'en etre sûr, c'est de débugger le code avec visual studio.
D'autre part, votre compte utilisateur de test a-t-il bien des droits cohérent au niveau du site ?
vous pourriez le mettre dans le groupe des visiteurs du site par exemple (c'est comme ca que j'ai fais pour tester votre code).
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel lundi 20 avril 2009 16:54
- Marqué comme réponse ZEMZEMI Amine lundi 20 avril 2009 21:04
-
Bonjour,
Le RunWithElevatedPrivilege permet d'impersonifier le compte système de SharePoint.
On l'utilise pour réaliser des opérations que ne peuvent pas réaliser les utilisateurs avec leurs autorisations.
Par exemple, si vous souhaitez qu'un événement déclenche une suppression d'un item, et que l'utilsateur ayant déclenché l'événement n'a pas les droits de suppression de l'item, votre code ne fonctionnera pas et une erreur sera générée. Il vous faudra dans ce cas de figure utiliser le RunWithElevatedPrivilege.
MCT, MCSD, MCSA, MCDBA & SharePoint Developer - http://blogs.coforcert.com/dntamack- Marqué comme réponse ZEMZEMI Amine lundi 20 avril 2009 21:09
Toutes les réponses
-
Bonjour,
Pour récupérer le fullname d'une assembly, j'utilise Reflector (il existe d'autres moyens mais je trouve que c'est le plus pratique).
Une fois une assembly chargée dans Reflector, vous pouvez la sélectionner pour voir son fullname.
Concernant le code de votre méthode ItemAdded, attention à la liberation des ressources : Il faudrait soit appeller web.Dispose(); en fin de méthode, soit utiliser un bloc using, qui se chargerait de le faire.
Ne pas respecter cette pratique pourrait vous causer de gros soucis de performance une fois votre solution déployée en production.
Je vous propose le code suivant :
public override void ItemAdded(SPItemEventProperties properties) { base.ItemAdded(properties); SPSite site = null;
SPWeb web = null; try {
site = new SPSite(properties.SiteId); web = site.OpenWeb(properties.RelativeWebUrl); //votre code
} catch (Exception ex) { //votre code
} finally{ if(web != null) web.Dispose();
if(site != null)
site.Dispose(); } }
Pour plus d'information sur le sujet de la liberation des ressources, je vous invite à regarder ce post de Phil (et les liens qu'il suggere) : http://blogs.developpeur.org/phil/archive/2009/01/30/sharepoint-2007-dispose-patterns-et-l-outil-spdisposecheck.aspx
Bons développements :)
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel jeudi 16 avril 2009 15:25
- Modifié Arnault Nouvel vendredi 17 avril 2009 15:04
-
-
Et bien c'est ce fullname qu'il faut utiliser comme 2eme argument à l'appel de EventReceivers.Add();
Je pensais que c'était ce qui posait problème :)
--
Pour le .bat, de mémoire c'est aussi le fullname qu'il faut spécifier pour désinstaller avec gacutils :
gacutils -uf "TestHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxxxxxxxxxxxxxxxxxxxx";
Y-a-t-il un problème avec l'installation de l'assembly dans le GAC via gacutils -if ? si oui, vérifiez que le chemin relatif de la .dll que vous spécifiez en paramètre est bien le bon chemin par rapport à votre répertoire courant. Si besoin, utilisez un chemin absolu..
--
Enfin, pour déployer votre SPItemEventReceiver, idéalement il faudrait utiliser une feature associée à un SPFeatureReceiver pour pouvoir éxécuter du code sur son activation et sa désactivation. C'est ce code qui ajouterait/retirerait votre eventreceiver sur la liste cible :
On créé une classe qui hérite de SPFeatureReceiver, et c'est dans la méthode FeatureActivated que l'on appellerait list.EventReceivers.Add(..);
Dans FeatureDeactivated, on ferait un list.EventReceivers.Remove().
un exemple d'utilisation de SPFeatureReceiver ici : http://panvega.wordpress.com/2008/10/10/how-to-implement-the-spfeaturereceiver-class-to-your-feature/
Est-ce que cela résoud votre problème ?
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel jeudi 16 avril 2009 15:58
-
Concernant le déploiement, il existe aussi une manière déclarative de déployer un event receiver, mais cela se fait soit au niveau d'une liste dont on connait l'identifiant de template (impacte donc toutes les listes du même template pour votre site), soit au niveau d'un content type (là encore, il faut connaitre son identifiant).
L'avantage de cette méthode c'est qu'il n'y a pas besoin d'éxécuter de code pour effectuer l'association, elle dépendra de l'activation/désactivation de la feature
Si tel est votre cas, je vous invite à lire l'article suivant : http://msdn.microsoft.com/en-us/library/ms453149.aspx
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel jeudi 16 avril 2009 16:09
-
Bonjour,
je suppose que vous utiliser un namespace dans votre projet.
Si oui, votre variable ClassName doit respecter la nomenclature
className = monNameSpace.maClasse
Sinon, hormis avec le reflector, pour récupérer votre PublicKeyToken, déployez votre assembly dans le GAC de votre machine de développement, puis une fois dans le GAC, faites un clic droit > Propriétés; vous verrez apparaitre le PublicKeyToken.
MCT, MCSD, MCSA, MCDBA & SharePoint Developer - http://blogs.coforcert.com/dntamack -
Bonjour,
Quelle la différence de cette méthode à celle que l'avez mentionné ci dessus. Autre chose, est ce que je dois passer par une feature pour déployer mon handler.
Voilà le tuto que j'ai lu eventhandler.
Je pense que j'ai un problème lors de la génération de l'assembly. La commande c'est bien gacutil, on le trouve exactement ? -
Bonjour,
avec un visual studio 2005, gacutil.exe est situé dans "C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin"
Un moyen simple de s'en servir est d'ouvrir une ligne de commande visual studio (afin que ce chemin soit déjà chargé) :
Démarrer, Programs, Microsoft Visual Studio 2005, Visual Studio Tools, Visual Studio command line prompt
Vous n'aurez alors pas à taper le chemin complet pour utiliser gacutil
En ce qui concerne les méthodes de déploiement d'un event receiver, il en existe 3 principales :
La méthode par code pur, expliquée dans le tutorial que vous avez cité
Cette méthode est la plus directe, mais requiert l'execution du code sur l'un des serveurs de votre ferme, dans une application console par exemple. A chaque fois que vous voulez associer votre handler à une liste, vous devrez l'executer. Il est pratique dans ce cas de spécifier l'url de la liste cible en paramètre de l'application console.
La méthode par feature, s'appuyant sur un SPFeatureReceiver
Cette méthode permet à l'administrateur d'un site d'activer/désactiver la feature à volonté, ce qui executera du code qui associera/désassociera votre handler à une liste. Malheureusement il n'est pas possible de laisser l'utilisateur choisir la liste à associer à votre handler, vous devez donc dans votre SPFeatureReceiver spécifier la liste cible "en dur", en la récupérant par exemple par son nom. On utilise en général cette méthode lorsque l'activation de la feature dépend d'une autre feature (s'activant en même temps) qui créé une liste avec un nom et une url pré-paramétrée. Le point important est d'avoir un moyen d'identifier de manière sûre la liste cible.
La méthode par feature, s'appuyant sur une association déclarative dans le xml de la feature
Cette méthode permet à l'administrateur d'un site d'activer/désactiver la feature à volonté, ce qui activera/désactivera l'association de votre handler à un type de liste (donc toutes les listes basées sur le template spécifié) ou à un content type. Cette méthode est très pratique pour associer un event receiver à toutes les listes créées à partir un type de liste personnalisé que vous avez développé, ou un de ceux définis par défaut dans SharePoint.
La méthode à utiliser dépend de votre besoin. Si il s'agit d'un besoin unique ou rare et que vous avez accès à un des serveurs de la ferme, la première méthode peut convenir. Si cet event receiver doit être utilisé dans plusieurs sites, il est préférable de réfléchir à une solution permettant aux administrateurs de l'activer eux-meme, dans ce cas on préfèrera les méthodes 2 et 3.
Vous n'etes donc pas obligé de passer par une feature, bien que ce soit préférable dans la plupart des cas.
Auriez-vous plus d'informations à nous fournir quant au problème lors de la génération de l'assembly ?
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel vendredi 17 avril 2009 09:47
-
J'ai un problème pour générer la solution dans la Gac : j'ai ouvert la console de visual studio et quand je tape
gacutil -if C:\Documents and Settings\Administrateur\Mes documents\Visual Studio 2008\Projects\TestHandler\TestHandler\bin\Debug\TestHandler
Il me dit option and inconnu ? -
c'est probablement à causes des espaces, essayez comme ceci :
gacutil -if "C:\Documents and Settings\Administrateur\Mes documents\Visual Studio 2008\Projects\TestHandler\TestHandler\bin\Debug\TestHandler.dll"
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel vendredi 17 avril 2009 11:47
-
Je vous remercie ca marche.
Concernant les types de déploiement je vous explique globalement qu'est ce que je souhaite réaliser :
Je dois faire une application qui permet de se connecter à un site, puis l'utilisateur choisit une liste et un content type et ajoute deux champs Lecteurs et modificateurs à chaque CT de la liste.
Par la suite un eventhandler est généré à chaque création et/ou modification d'un Item de la liste sélectionné : Cet event va casser l'héritage, récupérer la liste des lecteurs et des modificateurs et leur attribut des nouveaux droits sur l'Item.
Je pense que je dois utiliser la première méthode non ? -
Si c'est l'utilisateur qui doit sélectionner la liste sur laquelle attacher l'event receiver, effectivement, seule une solution par code est envisageable.
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel vendredi 17 avril 2009 12:34
-
D'accord, j'ai appliqué la première méthode et j'ai su comment récupérer la PublicKeyToken de l'assembly mais il y a une erreur de l'association de l'event à la liste :
string AssemblySignature = "DroitEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=08623ff6062721fc"; string ClassName = "Droit"; objSPWeb.Lists[listBox1.SelectedItem.ToString()].EventReceivers.Add(SPEventReceiverType.ItemAdded, AssemblySignature, ClassName);
L'erreur au niveau la 3 ème ligne : pe etre il ne trouve pas le nom de la classe ? -
Effectivement, comme l'a indiqué dnt91 plus haut, vous devez spécifier le nom la classe de votre event receiver, en précisant son namespace
la ligne devrait donc ressembler à
String className = "nom_du_projet.Droit";
Une fois encore, Reflector peut vous aider à vérifier le nom exact. Sélectionnez votre classe dans Reflector, et son nom complet devrait s'afficher (champ Name).
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel vendredi 17 avril 2009 13:03
-
Vous avez raison j'ai oublié d'ajouter le nom du projet.
En testant maitenant mon event j'ai remarqué que les droits ne sont pas modifiés : Lors de l'ajout d'un nouveau Item l'utilisateur saisit dans le champ "Lecteurs" les noms des users qui peuvent lire son item. Une fois l'item ajouté, seuls les utilisateurs qui ont le droit de lire peuvent lire l'Item. C'est ce que j'ai mis en haut de la pâge. -
J'explique un peu plus mon besoin :
Création d’un Event Handler qui va gérer la mise en place des autorisations sur le champ Lecteurs et Modificateurs que j'ai ajouté à mon Content typeSuppression de l’héritage
Ajout de l’autorisation « Contrôle totale » pour le propriétaire
Ajout de l’autorisation « Lecture seule » pour les utilisateurs du champ « Utilisateurs (Lecture seule) »
Ajout de l’autorisation « Collaboration » pour les utilisateurs du champ « Utilisateurs (Modification) »
-
Les droits sont correctement appliqués par votre code mais ne sont pas sauvegardés : il manque un item.Update() à la fin de la méthode.
Cela risque d'appeller votre event receiver en boucle infinie, il faut donc appeller this.DisableEventFiring() en début de méthode et this.EnableEventFiring() en fin de méthode. Cela aura pour effet de désactiver les event handler le temps que le votre finisse son traitement.
Est-ce que cela résoud votre problème ?
Il suffit ensuite de duppliquer et modifier très légèrement votre code de génération des SPRoleAssignment pour effectuer la meme manipulation pour les 2 autres autorisations..
Une remarque, votre méthode est appellé en asynchrone lorsque l'item a été ajouté, il est donc inutile de mettre un blog try-catch qui retourne un message d'erreur à l'utilisateur en cas d'erreur. Cette stratégie n'est appliquable que pour les événements synchrone, dans ItemAdding par exemple.
Il est impossible de prévenir l'utilisateur en cas d'erreur dans un événement asynchrone.
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel vendredi 17 avril 2009 15:00
-
Concernant le code que j'ai écrit je l'appelle à travers un bouton qui va attacher la liste à cet évènement. Est ce que le code va être appliquer tout le temps sur la liste à chaque nouvel Item ?Autre chose, je dois prendre en considération les autorisations en anglais et en francais donc est ce que vous savez à quoi correspondent ces autorisations :
« Contrôle totale »
« Lecture seule »
« Collaboration »
Quand j'utilise SPRoleType je ne trouve pas ces autorisations.
Merci
-
Bonjour,
Une fois un event receiver attaché à une liste sur l'événement ItemAdded, il sera toujours appelé lors de la création d'un élément. Attention donc à ne pas l'attacher plusieurs fois, auquel cas votre code serait exécuté plusieurs fois lors d'une création d'élément.
Contrôle total correspond à SPRoleType.Administrator,
Lecture seule correspond à SPRoleType.Reader,
Collaboration correspond à SPRoleType.Contributor.
http://blogs.developpeur.org/anouvel -
Bonjour,
Franchement, j'ai essayé mon code mais je ne comprends pas pourquoi il ne marche pas : j'ai créé un item avec le compte de l'administrateur et j'ai ajouté dans le champs lecteurs et modificateurs le user user1. Puis, j'ai changé l'utilisateur courant en user1 pour voir l'exécution mais il n'ya pas d'Item dans la liste malgré que le user peut voir l'item.
Voilà le code :public override void ItemAdded(SPItemEventProperties properties) { this.DisableEventFiring(); base.ItemAdded(properties); SPWeb web = null; try { web = new SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl); SPListItem item = web.Lists[properties.ListId].GetItemById(properties.ListItemId); // première étape, casser l'héritage des droits item.BreakRoleInheritance(false); // seconde étape, assigner les nouveaux droits #region Ajouter les droits Control total à l'auteur String loginAdmin = properties.UserLoginName; // SPFieldUserValue userAdminValue = (SPFieldUserValue)item["Créé par"]; SPUser userAdmin = web.Users[loginAdmin]; SPRoleDefinition roleDefAdmin = web.RoleDefinitions.GetByType(SPRoleType.Administrator); SPRoleAssignment roleAssignementAdmin = new SPRoleAssignment(userAdmin); roleAssignementAdmin.RoleDefinitionBindings.Add(roleDefAdmin); item.RoleAssignments.Add(roleAssignementAdmin); #endregion #region Ajouter les droits de lecture pour les lecteurs SPFieldUserValueCollection usersvaluesLecteurs = (SPFieldUserValueCollection)item["Lecteurs"]; for (int i = 0; i < usersvaluesLecteurs.Count; i++) { SPUser userLecteur = usersvaluesLecteurs[i].User; //on ajoute le user sur le dossier SPRoleDefinition roleDefLecteur = web.RoleDefinitions.GetByType(SPRoleType.Reader); SPRoleAssignment roleAssignementLecteur = new SPRoleAssignment(userLecteur); roleAssignementLecteur.RoleDefinitionBindings.Add(roleDefLecteur); item.RoleAssignments.Add(roleAssignementLecteur); } #endregion #region Ajouter les droits de modification pour les modificateurs SPFieldUserValueCollection usersvaluesModificateurs = (SPFieldUserValueCollection)item["Modificateurs"]; for (int i = 0; i < usersvaluesModificateurs.Count; i++) { SPUser userModificateur = usersvaluesModificateurs[i].User; //on ajoute le user sur le dossier SPRoleDefinition roleDefModificateur = web.RoleDefinitions.GetByType(SPRoleType.Contributor); SPRoleAssignment roleAssignementModificateur = new SPRoleAssignment(userModificateur); roleAssignementModificateur.RoleDefinitionBindings.Add(roleDefModificateur); item.RoleAssignments.Add(roleAssignementModificateur); } #endregion item.Update(); this.EnableEventFiring(); } catch (Exception ex) { properties.Cancel = true; properties.ErrorMessage = "Erreur dans l'Event ItemAdded : " + ex.Message; } finally { if (web != null) web.Dispose(); }
Je c que je vous embette mais franchement je suis bloqué.
Merci pour votre aide. -
-
Bonjour,
je viens d'essayer votre code, et chez moi il a fonctionné. C'est plutôt encourageant :)
Pour débusquer le problème, vous pouvez commencer par, avec le compte admin, cliquer sur le menu contextuel de l'élément puis sur View Permissions, cela permettrait de vérifier que les autorisations on bien été redéfinies. Vous devriez y trouver les autorisations que vous avez défini par code avec votre event receiver.
Vérifiez aussi que votre code s'execute entierement, en mettant un point d'arret dans votre méthode et en vous attachant avec visual studio aux processus w3wp.exe.
Les erreurs dans les event receivers asynchrones ne sont pas remontées à l'utilisateur, donc difficile de savoir si le traitement s'est correctement terminé. Le meilleur moyen d'en etre sûr, c'est de débugger le code avec visual studio.
D'autre part, votre compte utilisateur de test a-t-il bien des droits cohérent au niveau du site ?
vous pourriez le mettre dans le groupe des visiteurs du site par exemple (c'est comme ca que j'ai fais pour tester votre code).
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel lundi 20 avril 2009 16:54
- Marqué comme réponse ZEMZEMI Amine lundi 20 avril 2009 21:04
-
Vraiment merci Arnault pour votre aide vous m'avez tout expliqué.
Normalement, on peut détacher l'event de la liste par le code (comme on l'a attaché). Autre chose, j'ai lu dans le forum des discussions qui ressemblent à mon cas et ils parlent de la délégation de la méthode RunWithElevatedPrivilege(), à quoi sert ? -
Bonjour,
Le RunWithElevatedPrivilege permet d'impersonifier le compte système de SharePoint.
On l'utilise pour réaliser des opérations que ne peuvent pas réaliser les utilisateurs avec leurs autorisations.
Par exemple, si vous souhaitez qu'un événement déclenche une suppression d'un item, et que l'utilsateur ayant déclenché l'événement n'a pas les droits de suppression de l'item, votre code ne fonctionnera pas et une erreur sera générée. Il vous faudra dans ce cas de figure utiliser le RunWithElevatedPrivilege.
MCT, MCSD, MCSA, MCDBA & SharePoint Developer - http://blogs.coforcert.com/dntamack- Marqué comme réponse ZEMZEMI Amine lundi 20 avril 2009 21:09
-
Salut,
J'ai testé comme vous m'avez dit ça marche entre deux utilisateurs normaux. Mais quand l'utilisateur courant est l'administrateur et quand il ajoute un nouveau item en choisissant qui va lire toujours je ne peux visualiser l'item quand je change d'utilisateur.
Bon, normalement je dois aussi gérer la modification de l'item logiquement c'est le même code puisque à chaque fois on va lire la liste des lecteurs et des modificateurs.
Cordialement -
-
Bonjour,
Dans le code de modification, il faudrait supprimer tous les droits qui ont été créés à la création, avant de les redéfinir.
A part ça, le même code devrait fonctionner.
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel jeudi 23 avril 2009 05:41
-
-
BreakRoleInheritance permet simplement de casser l'héritage, il ne modifie en rien les autorisations définies. Dans votre cas puisque l'héritage est déjà cassé, l'appel à la méthode n'a aucun effet.
Pour supprimer les associations droit/utilisateur sur un élément, on utilise la méthode Remove() :
item.RoleAssignments.Remove(index);
Regardez le mail que je vous ai envoyé samedi, en pièce jointe il y a le projet dont je me suis servi pour vous aider. Au début de la méthode, je supprime tous les droits définis sur l'élément.
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel jeudi 23 avril 2009 11:19
-
-
-
-
L'adresse n'a pas l'air bonne, voici le code que j'ai utilisé pour tester le mécanisme :
public class LecteursER : SPItemEventReceiver { public override void ItemAdded(SPItemEventProperties properties) { UpdatePermissions(properties); } public override void ItemUpdated(SPItemEventProperties properties) { UpdatePermissions(properties); } private void UpdatePermissions(SPItemEventProperties properties) { this.DisableEventFiring(); try { using (SPSite site = new SPSite(properties.SiteId)) { using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl)) { SPList list = web.Lists[properties.ListId]; SPListItem item = list.GetItemById(properties.ListItemId); item.BreakRoleInheritance(false); //Supprime tous les droits pour les non-admins List<Int32> roleAssignmentsToDelete = new List<Int32>(); for (Int32 i = 0; i < item.RoleAssignments.Count; i++) { SPRoleAssignment ra = item.RoleAssignments[i]; if (ra.RoleDefinitionBindings.Count == 1 && ra.RoleDefinitionBindings[0].Type != SPRoleType.Administrator) roleAssignmentsToDelete.Add(i); } roleAssignmentsToDelete.Reverse(); //Suppression grâce à l'index, on va donc du plus grand au plus petit. foreach (Int32 index in roleAssignmentsToDelete) item.RoleAssignments.Remove(index); //Donne les droits aux nouveaux lecteurs SPFieldUserValueCollection userValues = item["Lecteurs"] as SPFieldUserValueCollection; SPRoleDefinition roleDef = web.RoleDefinitions.GetByType(SPRoleType.Contributor); if (userValues != null) { foreach (SPFieldUserValue userValue in userValues) { SPRoleAssignment roleAssignment = new SPRoleAssignment(userValue.User); roleAssignment.RoleDefinitionBindings.Add(roleDef); item.RoleAssignments.Add(roleAssignment); } } item.SystemUpdate(false); } } } finally { this.EnableEventFiring(); } } }
http://blogs.developpeur.org/anouvel -
-
Bonjour,
dans l'exemple la suppression d'éléments se fait via l'index de la collection, en le passant comme argument à la fonction Remove(index).
Sans le reverse(), le code commencerait par supprimer celui qui a l'index le plus petit. Les autres indexs seraient alors décalés, et les appels à Remove(index) se feraient avec de mauvaises valeurs en argument.
Le but de l'opération est de traiter les objets du plus grand au plus petit index, ce qui permet de les supprimer sans modifier l'ordre.
pour illustrer :
Si vous avez une List<Object> et que vous voulez supprimer le 2eme et le 3eme element, si vous faites list.Remove(2); puis list.Remove(3);, le 2eme appel va en réalité supprimer le 4eme élément et non le 3eme, car supprimer le 2eme fait que le 3eme se retrouve 2eme.
Par contre si vous supprimez d'abord le 3eme puis le 2eme, vous obtiendrez le résultat attendu.
http://blogs.developpeur.org/anouvel- Proposé comme réponse Arnault Nouvel jeudi 25 juin 2009 11:54
-
Bonjour, j'ai bien compris votre explication mais j'ai toujours un problème avec l'updateItem : En effet, quand je souhaite modifier les champs lecteurs et modificateurs de l'item je n'obtiens pas le résultat attendu quand je clique sur le menu "Gérer les autorisations" pour vérifier si la modification a bien eu lieu. J'obtiens toujours dans ces champs ce que j'ai créé avant c'est comme ci la suppression ne marche pas !
this.DisableEventFiring(); SPSite site = new SPSite(properties.SiteId); SPWeb web = site.OpenWeb(properties.RelativeWebUrl); try { SPList list = web.Lists[properties.ListId]; SPListItem item = list.GetItemById(properties.ListItemId); // première étape, casser l'héritage des droits item.BreakRoleInheritance(false); #region Supprimer tous les droits pour les non-admins List<Int32> roleAssignmentsToDelete = new List<Int32>(); for (Int32 i = 0; i < item.RoleAssignments.Count; i++) { SPRoleAssignment ra = item.RoleAssignments[i]; if (ra.RoleDefinitionBindings.Count == 1 ) //&& ra.RoleDefinitionBindings[0].Type != SPRoleType.Administrator //Remplir la liste qui contient les indices des anciens rôles à supprimer roleAssignmentsToDelete.Add(i); } roleAssignmentsToDelete.Reverse(); //Suppression grâce à l'index, on va donc du plus grand au plus petit. foreach (Int32 index in roleAssignmentsToDelete) item.RoleAssignments.Remove(index); #endregion #region Ajouter les droits Control total à l'auteur String loginAdmin = properties.UserLoginName; // SPFieldUserValue userAdminValue = (SPFieldUserValue)item["Créé par"]; SPUser userAdmin = web.Users[loginAdmin]; SPRoleDefinition roleDefAdmin = web.RoleDefinitions.GetByType(SPRoleType.Administrator); SPRoleAssignment roleAssignementAdmin = new SPRoleAssignment(userAdmin); roleAssignementAdmin.RoleDefinitionBindings.Add(roleDefAdmin); item.RoleAssignments.Add(roleAssignementAdmin); #endregion #region Ajouter les droits de lecture pour les lecteurs SPFieldUserValueCollection usersvaluesLecteurs = (SPFieldUserValueCollection)item["Lecteurs"]; for (int i = 0; i < usersvaluesLecteurs.Count; i++) { SPUser userLecteur = usersvaluesLecteurs[i].User; //on ajoute le user sur le dossier SPRoleDefinition roleDefLecteur = web.RoleDefinitions.GetByType(SPRoleType.Reader); SPRoleAssignment roleAssignementLecteur = new SPRoleAssignment(userLecteur); roleAssignementLecteur.RoleDefinitionBindings.Add(roleDefLecteur); item.RoleAssignments.Add(roleAssignementLecteur); } #endregion #region Ajouter les droits de modification pour les modificateurs SPFieldUserValueCollection usersvaluesModificateurs = (SPFieldUserValueCollection)item["Modificateurs"]; for (int i = 0; i < usersvaluesModificateurs.Count; i++) { SPUser userModificateur = usersvaluesModificateurs[i].User; //on ajoute le user sur le dossier SPRoleDefinition roleDefModificateur = web.RoleDefinitions.GetByType(SPRoleType.Contributor); SPRoleAssignment roleAssignementModificateur = new SPRoleAssignment(userModificateur); roleAssignementModificateur.RoleDefinitionBindings.Add(roleDefModificateur); item.RoleAssignments.Add(roleAssignementModificateur); } #endregion item.SystemUpdate(false); item.Update(); this.EnableEventFiring(); } finally { if (web != null) web.Dispose(); }
-
-
Bonjour,
je souhaite savoir pourquoi vous avez mis utiliséra.RoleDefinitionBindings.Count == 1
pour tester les droits avant de supprimer les autorisations.
J'ai essayé d'enlever cette condition et le code marchait bien mais avec cette condition j'arrive pas modifier les droits.
-
-
Bonjour,
Moi j'ai un probleme similaire au niveau de mon code. J'utilise un workflow pour de deplacer un fichier d'une bibliothèque à une autre puis je fait esureUser pour verifier si les utilisateurs sont bien affectés ou non. Mais lorsque j'ai debuggué j'a eu une exception de type Unauthorized access au niveau de cette methode Helper.SetCcpUsers(item, userIA, userIAL, userPOL, string.Empty);
voici le code :
private string CcpMoveToLegalRepository(string workflowStep, string documentStatus)
{
SPWorkflowTaskProperties taskProperties = workflowStep == CCPResources.WS_Confirmation_POLeader ? POLTaskProperties : PCTaskProperties;
SPUserToken userToken = WorkflowProperties.Web.EnsureUser(taskProperties.AssignedTo).UserToken;
Guid siteId = WorkflowProperties.SiteId;
Guid webId = WorkflowProperties.WebId;
Guid listId = WorkflowProperties.ListId;
int itemId = WorkflowProperties.ItemId;
SPListItem item = WorkflowProperties.Item;item[CTY_CcpDocumentIaPoWorkingArea.Field_Ccptaskassigneefornextstep_Id] = null;
item.SystemUpdate();string userIA = Helper.GetUserFieldValue(item, item[CTY_CcpDocumentIaPoWorkingArea.Field_Ccpiaeng_Id].ToString());
string userIAL = Helper.GetUserFieldValue(item, item[CTY_CcpDocumentIaPoWorkingArea.Field_Ccpial_Id].ToString());
string userPOL = Helper.GetUserFieldValue(item, item[CTY_CcpDocumentIaPoWorkingArea.Field_Ccppol_Id].ToString());
string userPC =
(item[CTY_CcpDocumentIaPoWorkingArea.Field_Ccppatentcounsel_Id] == null) ?
null : Helper.GetUserFieldValue(item, item[CTY_CcpDocumentIaPoWorkingArea.Field_Ccppatentcounsel_Id].ToString());string destinationUrl = GetDocumentDestinationURL(false);
// Update document metadata : DocumentStatus
Helper.UpdateDocumentMetadata(WorkflowProperties, documentStatus, null, "", null, null, null);// Save event in WorkflowHistory document metadata + Send MSMQ notification message for IMS
//
SPUser performedBy = WorkflowProperties.Web.EnsureUser(taskProperties.ExtendedProperties[SiteColumns.Field_Ccptaskperformedby.Id].ToString());Helper.SaveEvent(WorkflowProperties, workflowStep, WorkflowEvent.Completed, taskProperties);
#region Move item
//remove custom permissions
SPSecurity.RunWithElevatedPrivileges(
delegate()
{
using (SPSite site = new SPSite(siteId))
{
using (SPWeb web = site.OpenWeb(webId))
{
item = web.GetListItem(SPUrlUtility.CombineUrl(web.Url, WorkflowProperties.ItemUrl));
item.ResetRoleInheritance();
}
}
}
);//move item
using (SPSite site = new SPSite(siteId, performedBy.UserToken))
{
using (SPWeb web = site.OpenWeb(webId))
{
web.AllowUnsafeUpdates = true;// Move document to LegalRepository document library
item = web.GetListItem(SPUrlUtility.CombineUrl(web.Url, WorkflowProperties.Item.Url));
item.File.MoveTo(destinationUrl, SPMoveOperations.None);item = web.GetListItem(SPUrlUtility.CombineUrl(web.Url, destinationUrl));
//change content type
item["ContentTypeId"] = ContentTypes.CTY_CcpDocumentLegalRepository.ContentTypeId;
//ensure that users will be set correctly
Helper.SetCcpUsers(item, userIA, userIAL, userPOL, string.Empty);item.SystemUpdate();
web.AllowUnsafeUpdates = false;
}
}
SPSecurity.RunWithElevatedPrivileges(
delegate()
{using (SPSite site = new SPSite(siteId))
{
using (SPWeb web = site.OpenWeb(webId))
{
web.AllowUnsafeUpdates = true;
item = web.GetListItem(SPUrlUtility.CombineUrl(web.Url, destinationUrl));
item.ResetRoleInheritance();
// Initialize document read permissions for all groups
//SPUser systAcc = WorkflowProperties.Web.Users[CCPResources.SP_System_Account];
//Helper.InitDocumentPermissions(WorkflowProperties, systAcc.ToString(), SPRoleType.Reader);
Helper.InitDocumentPermissions(item, CCPResources.GROUP_ADMIN, SPRoleType.Administrator);
Helper.InitDocumentPermissions(item, CCPResources.GROUP_LMA, SPRoleType.Reader);
Helper.InitDocumentPermissions(item, CCPResources.GROUP_IA, SPRoleType.Reader);
Helper.InitDocumentPermissions(item, CCPResources.GROUP_IALeader, SPRoleType.Reader);
Helper.InitDocumentPermissions(item, CCPResources.GROUP_PatentCounsel, SPRoleType.Reader);
Helper.InitDocumentPermissions(item, CCPResources.GROUP_POLeader, SPRoleType.Reader);
Helper.InitDocumentPermissions(item, CCPResources.Group_LNM, SPRoleType.Reader);
Helper.SetDocumentWritePermissions(item, userPOL, true);
if (!string.IsNullOrEmpty(userPC) &&
!userPOL.Equals(userPC,StringComparison.InvariantCultureIgnoreCase))
Helper.SetDocumentWritePermissions(item, userPC, false);
item.SystemUpdate();
web.AllowUnsafeUpdates = false;
}
}
}
);
//reset permissions
//SPSecurity.RunWithElevatedPrivileges(
// delegate()
// {
// using (SPSite site = new SPSite(siteId))
// {
// using (SPWeb web = site.OpenWeb(webId))
// {
// item = web.GetListItem(SPUrlUtility.CombineUrl(web.Url, destinationUrl));
// item.ResetRoleInheritance();
// }
// }
// }
//);#endregion
return destinationUrl;
}
public static void SetCcpUsers(SPListItem item, string ia, string ial, string pol, string cc)
{
item[ACTY_CcpDocument.Field_Ccpiaeng_Id] = item.Web.EnsureUser(ia);
item[ACTY_CcpDocument.Field_Ccpial_Id] = item.Web.EnsureUser(ial);
item[ACTY_CcpDocument.Field_Ccppol_Id] = item.Web.EnsureUser(pol);
if (cc != string.Empty)
item[ACTY_CcpDocument.Field_Ccppatentcounsel_Id] = item.Web.EnsureUser(cc);
}
SVP Est ce que Vous avez une ptite idée sur ce probleme parce que j'ai essayé avec tout: Run with elevate Privileges et aussi AllowUnsafeUpdates mais j'arrive pas à comprendre
Merci