Archivo

Archive for 27 abril 2011

Microsoft Community Contributor 2011


Pues que el día de hoy me llega un correo de Microsoft con un reconocimiento: el Microsoft Community Contributor Award 2011. Vaya que fue una sorpresa.

Dear Fernando,

Congratulations! We’re pleased to inform you that your contributions to Microsoft online technical communities have been recognized with the Microsoft Community Contributor Award.

The Microsoft Community Contributor Award is reserved for participants who have made notable contributions in Microsoft online community forums such as TechNet, MSDN and Answers. The value of these resources is greatly enhanced by participants like you, who voluntarily contribute your time and energy to improve the online community experience for others.

mccposo2011

Ahora me siento culpable porque no he escrito mucho últimamente, así que ¡a redoblar esfuerzos!

MCC11_Logo_Vertical_Full-color

MCC_Logo_NEW

Categorías:Noticias

Cómo identificar si el usuario autenticado pertenece a un grupo de SharePoint


¿Recuerdan que el viernes les comentaba sobre cómo identificar si un usuario de SharePoint pertenece a un grupo cualquiera? A grandes rasgos, la única forma de hacerlo era mediante un proceso manual de obtener el usuario y buscar en sus grupos, o bien obtener el grupo y buscar sus usuarios: si no encontrábamos el elemento, no existía.

Pues bien, si ese usuario es el usuario actualmente autenticado, hay un camino más fácil: primero, obtenemos la referencia al SPGroup que queramos; y posteriormente, invocamos la propiedad SPGroup.ContainsCurrentUser. Esta propiedad nos devuelve true si el usuario autenticado pertenece a dicho grupo.

El codiguillo sería algo así:

private void MatchByGroup(HtmlTextWriter writer, string groupName, string userLogin)
{
    SPGroup spgroup = SPContext.Current.Web.SiteGroups[groupName];
    bool match = spgroup.ContainsCurrentUser;

    writer.Write("El grupo '{0}' contiene al usuario '{1}': {2}<br/>",
        spgroup.Name, userLogin, match);
}

Mucho más sencillo, ¿no?

Usando el control de búsqueda de usuarios


Cuando en una lista o biblioteca de documentos agregas un campo de tipo “Persona o Grupo”, al momento de editar el elemento verás un control como el que se muestra en la siguiente imagen, al lado de la fila “Cuenta”.

image

Este control cuenta con dos cosas útiles. La primera, cuando escribo algún nombre y hago clic en el primer iconito (el que muestra la palomita), el control valida si lo que escribí pertenece a algún usuario dentro de SharePoint / Directorio Activo. De ser así, lo muestra como tal, y en caso contrario lo marca como inválido.

image

La segunda funcionalidad es que, si no conocemos el nombre del usuario, podemos hacer clic en el segundo iconito (el del libro) y entonces un buscador aparecerá para ayudarnos a elegir alguno.

image

Sobra decir que este control es súmamente útil para buscar gente. Más aún, cuando hacemos algún componente para SharePoint, la gente esperará ver este control cuando tenga que ingresar gente, en lugar de un vil TextBox.

Afortunadamente, el control que hace todas estas monerías está disponible para nosotros en la clase PeopleEditor, ubicado en el espacio de nombres Microsoft.SharePoint.WebControls.

Utilizar esta clase es sencillo. Algunas propiedades son conocidas por nosotros, como AutoPostBack y Width. Otras son fáciles de adivinar: AllowEmpty nos permite determinar si el control debe quedar vacío o no (en caso de que sea false, si no ponemos algo el validador que lleva consigo nos lo hará saber); mientras que MultiSelect nos permite determinar si el control permitirá un solo elemento, o varios (el alto del control varía dependiendo de esto).

He aquí el un código de ejemplo que muestra lo anterior. Es un fragmento de un WebPart creado a guisa de ejemplo, perteneciente al método CreateChildControls.

_singleEditor = new PeopleEditor();
_singleEditor.ID = "_singleEditor";
_singleEditor.AutoPostBack = true;
_singleEditor.Width = new Unit(300, UnitType.Pixel);
_singleEditor.AllowEmpty = false;
_singleEditor.MultiSelect = false;

_multipleEditor = new PeopleEditor();
_multipleEditor.ID = "_multipleEditor";
_multipleEditor.AutoPostBack = true;
_multipleEditor.Width = new Unit(300, UnitType.Pixel);
_multipleEditor.AllowEmpty = true;
_multipleEditor.MultiSelect = true;

Todo más o menos sencillo, ¿no? Bueno, supongamos ahora que queremos pre-cargar nuestros controles con alguna información. Para ello, necesitamos el método UpdateEntities del control. Este método toma como parámetro un ArrayList (lo sé, lo sé, pero recordemos que WSS salió antes que .NET Frameowork 2.0), el cual debe contener cada uno de los usuarios a mostrar en el control. Cada entrada al arreglo debe ser de tipo PickerEntity, con su propiedad Key establecida al nombre del usuario o el de su cuenta. Por ejemplo:

PickerEntity entity = new PickerEntity();
entity.Key = "ASGARD\\freyja";
ArrayList entities = new ArrayList();
entities.Add(entity);
_singleLoadedEditor.UpdateEntities(entities);

En un control cuya propiedad MultiSelect sea true, podemos agregar varios elementos al arreglo. Por ejemplo, el siguiente código obtiene un grupo de SharePoint e itera sobre cada usuario, añadiéndolo al arreglo y por ende, al control PeopleEditor en cuestión.

entities = new ArrayList();
foreach (SPUser user in SPContext.Current.Web.SiteGroups["Asgard Æsir"].Users)
{
    entity = new PickerEntity();
    entity.Key = user.Name;
    entities.Add(entity);
}
_multipleLoadedEditor.UpdateEntities(entities);

¿A poco no gana en la vida? Así es como luce mi WebPart.

image

Chidito, ¿no? ¡Y profesional! Este es el código completo del WebPart mostrado en la imagen anterior.

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.WebControls;
using System.Web.UI.WebControls;
using System.Collections;

namespace Fermasmas.Wordpress.Com.WebParts
{
    public class PeopleEditorExample : WebPart
    {
        private PeopleEditor _singleEditor;
        private PeopleEditor _multipleEditor;
        private PeopleEditor _singleLoadedEditor;
        private PeopleEditor _multipleLoadedEditor;

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            _singleEditor = new PeopleEditor();
            _singleEditor.ID = "_singleEditor";
            _singleEditor.AutoPostBack = true;
            _singleEditor.Width = new Unit(300, UnitType.Pixel);
            _singleEditor.AllowEmpty = false;
            _singleEditor.MultiSelect = false;

            _multipleEditor = new PeopleEditor();
            _multipleEditor.ID = "_multipleEditor";
            _multipleEditor.AutoPostBack = true;
            _multipleEditor.Width = new Unit(300, UnitType.Pixel);
            _multipleEditor.AllowEmpty = true;
            _multipleEditor.MultiSelect = true;

            _singleLoadedEditor = new PeopleEditor();
            _singleLoadedEditor.ID = "_singleLoadedEditor";
            _singleLoadedEditor.AutoPostBack = true;
            _singleLoadedEditor.Width = new Unit(300, UnitType.Pixel);
            _singleLoadedEditor.AllowEmpty = false;
            _singleLoadedEditor.MultiSelect = false;

            _multipleLoadedEditor = new PeopleEditor();
            _multipleLoadedEditor.ID = "_multipleLoadedEditor";
            _multipleLoadedEditor.AutoPostBack = true;
            _multipleLoadedEditor.Width = new Unit(300, UnitType.Pixel);
            _multipleLoadedEditor.AllowEmpty = true;
            _multipleLoadedEditor.MultiSelect = true;

            Controls.Add(new Literal { Text = "Sencillo:<br/>" });
            Controls.Add(_singleEditor);
            Controls.Add(new Literal { Text = "<br/>Sencillo cargado:<br/>" });
            Controls.Add(_singleLoadedEditor);
            Controls.Add(new Literal { Text = "<br/>M&uacute;ltiple:<br/>" });
            Controls.Add(_multipleEditor);
            Controls.Add(new Literal { Text = "<br/>M&uacute;ltiple cargado:<br/>" });
            Controls.Add(_multipleLoadedEditor);

            PickerEntity entity = new PickerEntity();
            entity.Key = "ASGARD\\freyja";
            ArrayList entities = new ArrayList();
            entities.Add(entity);
            _singleLoadedEditor.UpdateEntities(entities);

            SPGroup group = SPContext.Current.Web.SiteGroups["Asgard Æsir"];
            entities = new ArrayList();
            foreach (SPUser user in group.Users)
            {
                entity = new PickerEntity();
                entity.Key = user.Name;
                entities.Add(entity);
            }
            _multipleLoadedEditor.UpdateEntities(entities);
        }
    }
}

Para finalizar, solo comentar una cosa curiosa con la que me topé cuando escribía el ejemplo de este texto: las llamadas a UpdateEntities tienen que hacerse después de agregar los controles al WebPart (es decir, después de hacer el Controls.Add). Si no, el UpdateEntities no reconocerá a los usuarios y presentará un comportamiento extraño. No sé por qué ocurre así, pero lo hace (haz la prueba si gustas). Si alguien sabe la explicación, compártala con el mundo.

¡Buen fin de semana!

Cómo identificar si un usuario de SharePoint pertenece a un grupo


Habrá ocasiones en las que querremos realizar determinada acción sólo si un usuario pertenece a cierto grupo. Por ejemplo, mostrar controles, permitir ediciones, regular la seguridad, etc. En esta entrada veremos como solucionar este problema.

Existen dos formas de enfocar el problema: a) podemos obtener el grupo en cuestión y ver si el usuario en cuestión pertenece a él, o bien b) obtenemos el usuario y revisamos todos sus grupos, hasta encontrar el que buscamos. Exploraremos las dos opciones.

En SharePoint, la clase SPUser identifica a un usuario, mientras que la clase SPGroup identifica a un grupo. Un usuario cualquiera cuenta con una propiedad llamada Groups, de tipo SPGroupCollection, la cual contiene una referencia a los grupos del usuario. Adicionalmente, un grupo cuenta con una propiedad llamada Users, de tipo SPUserCollection, la cual contiene todos los usuarios pertenecientes al grupo. Así, vemos que para resolver nuestro problema con cualquiera de los dos enfoques, sólo tenemos que iterar sobre un SPUserCollection o SPGroupCollection, según sea el caso. Tristemente, no exsite un método llamado “ContainsGroup” o “ContainsUser” para estas colecciones, así que tendremos que iterar. Nos podemos apoyar en LINQ, sin embargo.

Vamos a hacer un ejemplo. En nuestro sitio, creemos un par de grupos y añadámosle algunos usuarios. En mi sitio, yo he creado el grupo “Asgard Æsir”, al cual pertenecen los usuarios ASGARD\odin, ASGARD\thor y ASGARD\tyr; y el sitio “Asgard Vanir”, al cual pertenecen los usuarios ASGARD\freyja, ASGARD\skadi y ASGARD\loki. La siguiente imagen lo ilustra.

image

Ahora, creemos un simple WebPart y añadámosle dos métodos: MatchByGroup, el cual tome como parámetros el nombre de algún grupo y escriba si un usuario cualquiera pertenece a éste o no; y MatchByUser, el cual tome como parámetro el nombre de algún usuario y escriba si pertenece a un grupo cualquiera.

El siguiente es el código de MatchByGroup.

private void MatchByGroup(HtmlTextWriter writer, string groupName, string userLogin)
{
    SPGroup spgroup = SPContext.Current.Web.SiteGroups[groupName];
    var query = from SPUser user in spgroup.Users
                where user.LoginName.Equals(userLogin)
                select user;
    bool match = query.Count() > 0;

    writer.Write("El grupo '{0}' contiene al usuario '{1}': {2}<br/>", 
        spgroup.Name, userLogin, match);
}

Como podemos ver, primero obtenemos el grupo y hacemos una consulta LINQ a la propuedad SPGroup.Users en busca de aquellos usuarios cuyo LoginName concuerde. Si la consulta nos devuelve más de un elemento, entonces sí lo hace.

Así, el algoritmo para el método MatchByUser es muy similar, solo que hacemos la consulta LINQ sobre SPUser.Groups. Aquí está el código.

private void MatchByUser(HtmlTextWriter writer, string groupName, string userLogin)
{
    SPUser user = SPContext.Current.Web.AllUsers[userLogin];
    var query = from SPGroup spgroup in user.Groups
                where spgroup.Name.Equals(groupName)
                select spgroup;
    bool match = query.Count() > 0;

    writer.Write("El usuario '{0}' pertenece al grupo '{1}': {2}<br/>",
        user.LoginName, groupName, match);
}

Easy peasy. En nuestro WebPart, solo falta sobreescribir el método RenderContents e invocar a nuestros métodos. Por ejemplo:

protected override void RenderContents(HtmlTextWriter writer)
{
    base.RenderContents(writer);

    writer.Write("<h2>Por grupo</h2>");
    MatchByGroup(writer, "Asgard Vanir", "ASGARD\\thor");
    MatchByGroup(writer, "Asgard Vanir", "ASGARD\\freyja");
    MatchByGroup(writer, "Asgard Vanir", "ASGARD\\loki");
    writer.Write("<h2>Por usuario</h2>");
    MatchByUser(writer, "Asgard Vanir", "ASGARD\\thor");
    MatchByUser(writer, "Asgard Vanir", "ASGARD\\freyja");
    MatchByUser(writer, "Asgard Vanir", "ASGARD\\loki");
}

Con este código, así es como luce nuestro WebPart.

image

Y ya por último, para los flojos que gustan de hacer copy-paste, les dejo el código completo del WebPart.

using System;
using System.Linq;
using System.Web.UI;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;

namespace Fermasmas.Wordpress.Com.WebParts
{
    public class UserGroupExample : WebPart
    {
        public UserGroupExample()
        {
        }

        private void MatchByGroup(HtmlTextWriter writer, string groupName, string userLogin)
        {
            SPGroup spgroup = SPContext.Current.Web.SiteGroups[groupName];
            var query = from SPUser user in spgroup.Users
                        where user.LoginName.Equals(userLogin)
                        select user;
            bool match = query.Count() > 0;

            writer.Write("El grupo '{0}' contiene al usuario '{1}': {2}<br/>",
                spgroup.Name, userLogin, match);
        }

        private void MatchByUser(HtmlTextWriter writer, string groupName, string userLogin)
        {
            SPUser user = SPContext.Current.Web.AllUsers[userLogin];
            var query = from SPGroup spgroup in user.Groups
                        where spgroup.Name.Equals(groupName)
                        select spgroup;
            bool match = query.Count() > 0;

            writer.Write("El usuario '{0}' pertenece al grupo '{1}': {2}<br/>",
                user.LoginName, groupName, match);
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            base.RenderContents(writer);

            writer.Write("<h2>Por grupo</h2>");
            MatchByGroup(writer, "Asgard Vanir", "ASGARD\\thor");
            MatchByGroup(writer, "Asgard Vanir", "ASGARD\\freyja");
            MatchByGroup(writer, "Asgard Vanir", "ASGARD\\loki");
            writer.Write("<h2>Por usuario</h2>");
            MatchByUser(writer, "Asgard Vanir", "ASGARD\\thor");
            MatchByUser(writer, "Asgard Vanir", "ASGARD\\freyja");
            MatchByUser(writer, "Asgard Vanir", "ASGARD\\loki");
        }
    }
}

Buen fin de semana.