Search Driven Development (III): El WebPart de Refinamiento

Muy buenas a todos de nuevo,

Antes de nada, os deseo una Feliz Navidad a todos. Hoy quiero seguir profundizando un poco más en el concepto de Search Driven Development. Vamos a trabajar con el WebPart de refinamiento. Al igual que el Content Search WebPart, el de refinamiento es completamente configurable de una forma muy sencilla. Mucho más que lo era el WebPart de refinamiento en SharePoint 2010.

Además, y aunque no es objeto de este post, también se pueden crear plantillas para estos refinadores de búsqueda, tal y como hacíamos con los tipos de resultado.

Para explicar como trabajar con el WebPart de refinamiento he planteado un escenario en el que dispongo de un catálogo de formaciones y he creado al igual que hacía en los anteriores post, su respectiva página de catálogo y elementos de catálogo, configurando posteriormente el Content Search WebPart de cada uno.

Primeros Pasos con SharePoint OnLine: Search Driven Development

Search Driven Development en SharePoint (II): Catálogos y Elementos de Catálogo

El tipo de Contenido que he creado para el catálogo es el siguiente:

Captura de pantalla 2014-12-26 a las 2.24.48

Una vez creado el catálogo y su funcionalidad, añadimos a la página del catálogo el WebPart de refinamiento, dándonos un aspecto como el siguiente.

Captura de pantalla 2014-12-26 a las 2.20.45

El caso es que para nuestro catálogo, no es suficiente con los refinadores por defecto que nos carga el WebPart de refinamiento, queremos establecer nuestros propios refinadores, basados en el tipo de contenido que hemos definido. En nuestro caso queremos poder refinar nuestro catálogo por: Tipo de Formación, Autor, Temática y Valoración.

Definiendo las propiedades administradas para el refinamiento

Todas las opciones de refinamiento de nuestro WebPart se basan en propiedades administradas de nuestro esquema de búsqueda. Pero lo harán en unas propiedades especiales que en nuestro esquema aparecen con el nombre de: RefinableString, RefinableInt, RefinableDouble, RefinableDate, en función del tipo de dato que representa cada una, disponiendo de un número elevado de cada una de ellas para poder configurar correctamente nuestras propiedades administradas de refinamiento.

Lo que tendremos que hacer es, asociar las propiedades rastreadas que queramos usar en el refinamiento a las propiedades administradas correspondientes. Vamos a ver como hacer esto.

Para empezar vamos a Configuración del sitio->Esquema de Búsqueda de la administración de la colección de sitios (a nivel de sitio no tenemos permisos para hacerlo) y accederemos al esquema de búsqueda de la colección de sitios.

Captura de pantalla 2014-12-26 a las 2.40.16

Lo que haremos ahora, es ir a las distintas propiedades administradas para asociarlas adecuadamente. En mi ejemplo, quiero añadir cuatro refinadores, tres pueden ser mapeados como cadena y uno como número. Las propiedades administradas de refinamiento tienen números correlativos asignados (por ejemplo RefinableString00 a RefinableString99), así que seleccionamos la propiedad que queremos mapear y entramos a ella.

Captura de pantalla 2014-12-26 a las 2.46.12

Una vez dentro, tenemos que asignar las propiedades rastreadas. Para ello, hacemos click en asignar propiedades.

Captura de pantalla 2014-12-26 a las 2.46.24

Captura de pantalla 2014-12-26 a las 2.46.48

Buscamos la propiedad rastreada que queramos mapear, por defecto SharePoint, para cada columna que hayamos definido crea dos propiedades rastreadas, como las que vemos a continuación:

Captura de pantalla 2014-12-26 a las 2.48.36

Para el refinamiento, tenemos que seleccionar la propiedad que tiene la forma ows_<nombre de la propiedad>. Seleccionamos ésta y damos a aceptar, luego guardamos los cambios hechos en la propiedad administrada y, en nuestro caso, como queríamos crear cuatro refinadores personalizados, repetimos la tarea para el resto de refinadores.

Personalizando el WebPart de refinamiento

Una vez que ya hemos definido los refinadores personalizados que vamos a utilizar, podemos ir a la página del catálogo para configurar el WebPart de refinamiento. Para ello nos iremos a las propiedades de dicho WebPart y la opción de «Elegir refinadores».

Captura de pantalla 2014-12-26 a las 3.00.20

Captura de pantalla 2014-12-26 a las 3.00.38

Por defecto nos aparecen los refinadores que vemos en la imagen anterior. En nuestro caso, queremos cambiarlos por los que habíamos definido en el paso anterior. Por lo que cambiamos los refinadores por defecto por los siguientes: RefinableString01, RefinableString02, RefinableString03, RefinableInt01.

Captura de pantalla 2014-12-26 a las 3.03.36

Si hacemos click sobre cada uno de los refinadores podemos cambiar algunos aspectos de la visualización de los mismos. Entre otras cosas, nombre de ese refinador a  la hora de mostrarlo, tipo de plantilla (en función del tipo de refinador), y aspectos de configuración que varían en función del tipo de refinador que hayamos seleccionado.

Captura de pantalla 2014-12-26 a las 3.06.17

Captura de pantalla 2014-12-26 a las 3.06.35

Cuando hayamos configurado todos los refinadores, pulsamos aceptar y guardamos los cambios en el WebPart, con lo que ya tendremos nuestra página de Catálogo con unos refinadores personalizados y ajustados a nuestras necesidades. Es posible, que cuando se hayan definido los mismos, inicialmente, si no se ha realizado todavía una re-indexación de la lista posterior al mapeo adecuado de todas la propiedades administradas, no aparezca nada, esto se subsanará en cuestión de minutos, cuando la re-indexación se complete correctamente. Este es el aspecto que sin nada de diseño, nos queda del Content Search WebPart y el WebPart de refinamiento.

Captura de pantalla 2014-12-26 a las 3.11.27

Y nada más por hoy, espero que toda esta serie de artículos relacionados con el Search Driven Development, os estén siendo de utilidad. Os dejo algunos enlaces que me han servido a la hora de preparar el post.

http://blogs.technet.com/b/tothesharepoint/archive/2013/06/19/stage-14-configure-refiners-for-faceted-navigation.aspx

http://blogs.technet.com/b/tothesharepoint/archive/2013/11/11/how-to-add-refiners-to-your-search-results-page-for-sharepoint-2013.aspx

Un saludo.

Introducción al uso de Display Templates en SharePoint OnLine

Muy buenas de nuevo a todos,

En mis anteriores entradas he estado hablando sobre como podríamos usar los Content Search Web Part para hacer personalizaciones de nuestros sitios sin escribir ninguna línea de código. Habíamos conseguido una página que nos mostraba un catálogo de elementos y enlaces a la página donde podíamos ver el detalle de los elementos de dicho catálogo.

Primeros Pasos con SharePoint OnLine: Search Driven Development

Search Driven Development en SharePoint (II): Catálogos y Elementos de Catálogo

En ambas entradas os hablaba de la posibilidad de personalizar el diseño de esos resultados para hacerlos más atractivos e integrarlos con el branding de nuestro sitios. Para los que hayáis trabajado con la personalización de los resultados de búsqueda en SharePoint 2010, os habréis topado seguro con las plantillas XSL que nos obligaban a saber manejar XSLT para la creación de las mismas. Con SharePoint OnLine y 2013 todo este approach ha cambiado, dentro de toda la renovación de la plataforma para hacerla más ligera y cercana a las nuevas tecnologías. Ahora vamos a poder trabajar directamente con HTML y Javascript, lo que seguro que nos va a resultar muy interesante. Todo esto es lo que vamos a ver al hablar de los Display Templates. Nuestro objetivo va a ser, pasar de esto:

Captura de pantalla 2014-12-12 a las 19.58.55
Captura de pantalla 2014-12-13 a las 23.25.54

A una visualización de los resultados de nuestro Content Search Web Part como estos:

Captura de pantalla 2014-12-20 a las 15.28.29
Captura de pantalla 2014-12-20 a las 15.28.43

Aunque no se trata de un diseño muy elaborado, si que nos va a servir para ver que de una forma muy sencilla vamos a poder modificar la visualización de los resultados de búsqueda. Antes de nada, os voy a mostrar algunos enlaces que he utilizado para saber como usar los Display Templates.

http://blogs.technet.com/b/tothesharepoint/archive/2013/05/28/stage-11-upload-and-apply-display-templates-to-the-content-search-web-part.aspx

http://www.compartimoss.com/revistas/numero-17/introduccion-plantillas-elementos-contenido-display-templates

La información de nuestros Display Templates la vamos a encontrar en dos sitios. Si queremos editar las propiedades de las plantillas ya subidas, iremos al administrador de diseños al que podemos acceder de la siguiente manera, donde en el apartado de «Editar plantillas para mostrar», encontraremos las plantillas ya cargadas:

Captura de pantalla 2014-12-20 a las 15.49.54

Si por el contrario queremos añadir nuevas plantillas lo haremos a través de Configuración del sitio->Páginas maestras y diseños de página->Display Templates->Content Web Parts

Captura de pantalla 2014-12-20 a las 15.53.45

Cuando accedemos al lugar que nos permitirá añadir nuevas plantillas, vemos que cada una de las plantillas ya subidas tiene dos archivos, uno .html y otro .js. Nosotros solo tendremos que crear el .html con la plantilla, el archivo con extensión .js se crea automáticamente al subir el anterior y es transparente para nosotros, este archivo contiene la sustitución que hace SharePoint de una serie de etiquetas especiales que se usan en las plantillas, por las correspondientes que haya que usar.

En nuestro caso, para lograr el objetivo que os he mostrado, vamos a crear dos plantillas, una para los elementos cuando están dentro del catálogo y otra para la página que muestra el detalle de uno de los elementos del catálogo

¿Como creamos una plantilla personalizada?

Como hemos dicho antes, una plantilla es un archivo .html con una serie de etiquetas especiales. Voy a mostraros como es una plantilla y después os explicaré algunos aspectos que hay que tener en cuenta.

<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
<head>
    <title>Plantilla de Ejemplo</title>
  
    <!--[if gte mso 9]><xml>
    <mso:CustomDocumentProperties>
    <mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
    <mso:ManagedPropertyMapping msdt:dt="string">
        'Title'{Título}:'Title',
        'Skills'{Capacidades}:'CapacidadesOWSTEXT',
        'SecondaryFileExtension',
        'ContentTypeId'
    </mso:ManagedPropertyMapping>
    <mso:MasterPageDescription msdt:dt="string">Este es el ejemplo de una plantilla para resultados de elementos de busqueda</mso:MasterPageDescription>
    <mso:ContentTypeId msdt:dt="string">0x01006BCAA0AD8F40D041AD8D1579799074B6</mso:ContentTypeId>
    <mso:TargetControlType msdt:dt="string">;#Content Web Parts;#SearchResults;#</mso:TargetControlType>
    <mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
    </mso:CustomDocumentProperties></xml><![endif]-->
</head>
  
<body>
  
    <div id="ExampleSearchDrivenSolution">
  
<!--#_
    var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_exampleTemplate_");
  
    var linkURL = $getItemValue(ctx, "Link URL");
    linkURL.overrideValueRenderer($urlHtmlEncode);
  
    var title = $getItemValue(ctx, "Title");

  
    var skills = $getItemValue(ctx, "Skills");
  
    var containerId = encodedId + "container";
  
 _#-->
  
        <div id="_#= containerId =#_" style="float:left;width:25%;margin-left:0.5em;border:1px solid #CCC; min-height:25em;background-color:#EEE;cursor:pointer;position:relative;" onclick="window.location.href = '/sites/organizer/autores/_#= title =#_'">
            <span style="color:red;">_#= title =#_</span>
            <p style="text-decoration:underline;position:absolute;bottom:0.5em;">_#= skills =#_</p>
        </div>
  
    </div>
</body>
</html>
  • El primer aspecto importante se encuentra entre las líneas 5 y 18. Aquí se define un XML donde se definirán los parámetros de la plantilla. Lo más importante tiene que ver con lo que se define en la etiqueta «mso:ManagedPropertyMapping», que es donde se definen las propiedades administradas que serán mapeadas en la plantilla y que usaremos después en la misma para mostrar los distintos campos del elemento devuelto por la búsqueda.
  • Con las etiquetas «<!–#_» y «_#–>» podremos escribir todo el código Javascript que queramos dentro de nuestra plantilla.
  • Haciendo uso de las etiquetas «_#=» y «=#_» podremos hacer uso de variables de Javascript que hayamos definido previamente
  • Es importante tener en cuenta que solo el contenido que aparezca en el primer »
    <div>» será visible dentro de nuestra plantilla.

Este es el código que he usado para la plantilla de los elementos que forman parte del catálogo. A continuación os muestro la que he usado para el detalle de los elementos. La diferencia, a parte del diseño, se encuentra en las propiedades administradas que se mapearán en cada caso.

<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
<head>
    <title>Plantilla de Ejemplo para elementos</title>
  
    <!--[if gte mso 9]><xml>
    <mso:CustomDocumentProperties>
    <mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
    <mso:ManagedPropertyMapping msdt:dt="string">
        'Link URL'{Dirección URL del vínculo}:'Path',
        'Title'{Título}:'Title',
        'Skills'{Capacidades}:'CapacidadesOWSTEXT',
        'Email'{Email}:'EmailOWSTEXT;,
        'WebSite'{Sitio personal}:'PersonalWebsiteOWSURLH;,
        'SecondaryFileExtension',
        'ContentTypeId'
    </mso:ManagedPropertyMapping><mso:MasterPageDescription msdt:dt="string">Este ejemplo se utiliza para el elemento de la lista</mso:MasterPageDescription>
    <mso:ContentTypeId msdt:dt="string">0x01006BCAA0AD8F40D041AD8D1579799074B6</mso:ContentTypeId>
    <mso:TargetControlType msdt:dt="string">;#Content Web Parts;#SearchResults;#</mso:TargetControlType>
    <mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
    <mso:HtmlDesignConversionSucceeded msdt:dt="string">True</mso:HtmlDesignConversionSucceeded>
    </mso:CustomDocumentProperties></xml><![endif]-->
</head>
  
<body>
  
    <div id="ExampleSearchDrivenSolution">
  
<!--#_
    var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_exampleTemplate_");
  
    var title = $getItemValue(ctx, "Title");
  
    var skills = $getItemValue(ctx, "Skills");

    var mail = $getItemValue(ctx, "Email");
  
    var website = $getItemValue(ctx, "WebSite");
  
    var containerId = encodedId + "container";
  
 _#-->
        <h2>Nombre: _#= title =#_</h2>

        <span style="display:block;margin-top:1em;font-weight:bold;font-size:1.2em;">Descripción de las habilidades</span>
        <p>_#= skills =#_</p>

        <span style="display:block;margin-top:1em;font-weight:bold;font-size:1.2em;">¿Deseas ir a su web para conocer más sobre este autor?</span>
        <a href="_#= website =#_">_#= website =#_</a>

        <span style="display:block;margin-top:1em;font-weight:bold;font-size:1.2em;">¿Quieres ponerte en contacto con este autor?</span>
        <a href="mailto:_#= mail =#_">_#= mail =#_</a>
  
    </div>
</body>
</html>

¿Cómo subimos una plantilla personalizada?

Una vez que ya hemos definido nuestras plantillas, vamos a añadirlas a nuestro sitio de SharePoint para poder usarlas. Para ello, seguimos la ruta que ya indicamos antes, para entrar al sitio donde podremos subirla. En nuestra Ribbon, desplegamos la opción de «Nuevo Documento» y hacemos click en «Plantillas para mostrar de elementos»:

Captura de pantalla 2014-12-20 a las 16.30.50

A continuación seleccionamos la plantilla a subir,

Captura de pantalla 2014-12-20 a las 16.31.12

Por último se carga la pantalla de propiedades de la plantilla, donde vemos precargadas las propiedades que ya definimos en el código de la misma. Si no lo hemos hecho en el código de la plantilla, aquí deberemos indicar el Tipo de Contenido asociado, el título de plantilla, el tipo de control de destino y el Archivo Asociado.

Captura de pantalla 2014-12-20 a las 16.31.30

Una vez hecho esto, veremos que la plantilla se ha añadido correctamente a nuestra lista de plantillas y que efectivamente se ha creado asociado al .html el .js . Para que esté disponible para ser usada, tenemos que ir al administrador de diseños y aprobar la plantilla que acabamos de subir que estará en estado «Borrador» en ese momento.

Captura de pantalla 2014-12-20 a las 16.49.46

Tras esto la plantilla ya estará disponible para usarla en nuestro Content Search WebPart. El proceso para subir una nueva plantilla lo repetiremos para las dos plantillas de nuestro sitio.

Usando la plantilla en el Content Search WebPart

El último paso que nos queda es cargar las plantillas en cada uno de los Content Search WebPart, por un lado el que se encuentra en la página que muestra el catálogo y por otro el de la página que nos muestra los elementos del catálogo, usando en cada caso la plantilla deseada

Para ello, editamos el web part de la página correspondiente, seleccionando la plantilla que queremos usar como vamos a ver a continuación.

Captura de pantalla 2014-12-20 a las 17.01.34

En el apartado de plantillas para mostrar de las propiedades del webpart, marcamos Usar una plantilla única para mostrar elementos y ahí seleccionamos nuestra plantilla

Captura de pantalla 2014-12-20 a las 17.01.58

Una vez hagamos esto con las dos plantillas, ya tendremos las mismas funcionando y podremos ver los resultados de búsqueda con el diseño que queríamos.

Espero que os resulte interesante la información. Un saludo a todos

Trabajando con Sharepoint: controlando el acceso a páginas del sistema

Buenas a todos.

Hoy os quiero contar como resolví un requisito que me plantearon en uno de los proyectos que he realizado recientemente en Sharepoint 2010 en mi empresa. Con este proyecto, hemos hecho un branding completo del sitio y los usuarios solo pueden navegar a través de las páginas que hemos habilitado. Haciendo un análisis del proyecto, el departamento de seguridad informática detectó que si el usuario en vez de escribir la URL correcta, p.e.: http://misitio/sitepages/pagina1.aspx, por error solo escribía http://misitio/sitepages, SharePoint le redirigía a la página /sitepages/forms/allpages.aspx, además comprobaron que también podían acceder a las URL propias de SharePoint.

Eso permitía ver al usuario lugares del sitio que no se deseaban, y el requisito era evitar que esto se pudiera hacer, y permitir que solo los administradores pudieran hacerlo. Después de intentarlo de varias formas, hice una pregunta en el Blog de Desarrollo de SharePoint en español que recomiendo a todo el mundo y que os enlazo a continuación:

https://social.msdn.microsoft.com/Forums/es-ES/f3d5c716-b592-4630-8c80-796853441fb5/limitar-el-acceso-a-sitepagesformsallpagesaspx?forum=mossdeves

Finalmente opté por la opción de desarrollar un webpart. En el proyecto tengo definida una masterpage para las páginas a las que tiene acceso el usuario, mientras que el resto de páginas (las propias de Sharepoint incluidas) siguen teniendo la masterpage por defecto.

El webpart que definí se inserta en la masterpage por defecto. En dicho webpart se indica, a través de las propiedades, los grupos que no tendrán acceso a la página en cuestión, separados por «;». Si un usuario intenta acceder a esa página y pertenece a uno de los grupos prohibidos, entonces se hace el redirect a la página inicial, evitando así el acceso a los usuarios, a aquellas partes de SharePoint que no quiero. Os dejo el código del webpart a continuación

public INT_CONTROL_ACCESO WebPartControl { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            this.WebPartControl = this.Parent as INT_CONTROL_ACCESO;

            string avoidListstring = "";

            if (this.WebPartControl.avoidAccess != null)
                avoidListstring = this.WebPartControl.avoidAccess;

            Literal1.Text = "Not Allowed: " + this.WebPartControl.avoidAccess;


            List<string> avoidList = splitAvoidGroupList(avoidListstring);
            List<string> groups = getCurrentUserGroups();

            if (isInAvoidGroup(avoidList, groups))
            {
                Response.Redirect("/");
            }
        }

        private List<string> splitAvoidGroupList(string list)
        {
            List<string> avoidGroup = new List<string>();
            string[] avoidlist = list.Split(';');

            foreach (string item in avoidlist)
            {
                avoidGroup.Add(item);
            }

            return avoidGroup;
        }

        private bool isInAvoidGroup(List<string> avoidGroup, List<string> groups)
        {
            foreach (string item in groups)
                if (avoidGroup.Contains(item)) return true;

            return false;
        }

        private List<string> getCurrentUserGroups()
        {
            List<string> groups = new List<string>();

            foreach (SPGroup group in SPContext.Current.Web.CurrentUser.Groups)
            {
                groups.Add(group.Name);
            }

            return groups;
        }

Como veis el funcionamiento es muy sencillo:

  1. Se obtienen de las propiedades del webpart los grupos prohibidos.
  2. Se buscan los grupos a los que pertenece el usuario que está accediendo.
  3. Se comprueba si dichos grupos están en la lista y en su caso se hace el redirect

La verdad es que desconozco si es la forma más «elegante» de resolver este problema o hay alguna más recomendable. Os animo a que si conocéis alguna forma mejor lo comentéis y lo incluyo en la entrada como solución.

Espero que si se os plantea el mismo requerimiento que a mi, os sea de utilidad.

Saludos.