Libros - Repositorios

Hola a todo@s, en la siguiente entrada y continuando con la serie de entradas en el blog La librería, se va a seguir definiendo otras estructuras y recursos necesarios para la gestión de libros.

He de informar que, en esta entrada se hace referencias términos y conceptos, ya explicados en la entrada Tipos de géneros de libros - Repositorio, por lo que recomiendo su lectura antes de continuar.

En esta entrada se pretende afianzar los conceptos aprendidos en anteriores entradas, y seguir evolucionando en el desarrollo de aplicaciones en SharePoint online, a través de los siguientes objetivos:

  • Definir el repositorio de almacenamiento de los tipos de monedas.

  • Definir el repositorio de almacenamiento de los libros.

  • Adaptar la plantilla de aprovisionamiento a las nuevas necesidades.

  • Importar plantilla de aprovisionamiento.

  • Aprovisionar entorno con datos en una lista y otros recursos.

He de informar que, mientras desarrollada este ejercicio y se ejecutaba los diferentes scripts de PowerShell implicados, en la consola se informaba que se disponía de una versión actualizada de SharePoint PnP.

ADVERTENCIA: A newer version of PnP PowerShell is available: 3.6.1902.2. Consider upgrading.

Se procedió a actualizar SharePoint PnP a una versión más reciente, ejecutando el siguiente comando.

Install-Module SharePointPnPPowerShellOnline -SkipPublisherCheck -AllowClobber -force

Definir el repositorio de almacenamiento de los tipos de monedas

Antes de crear el repositorio donde almacenar la información de los libros, se va a crear otro repositorio para almacenar los tipos de monedas (Euro, Libra esterlina, Dólar, etc.…), que se va a utilizar posteriormente en la gestión de los libros, relacionado directamente con el precio del libro.

He de informar que, con esta información adicional, al visualizar el precio del libro en el componente SPfx de la gestión de los libros, el precio se visualizará con el formato de moneda que se configure. Esto es posible, gracias a que se va a usar un componente React de terceros (react-currency-formatter - npm) que se encarga de formatear el precio según el tipo de moneda proporcionado.

La definición de este repositorio se va a realizar sobre una lista personalizada, con las mismas características que la definición de la lista de tipos de géneros de libros. Con la diferencia de tener que crear una columna personalizada, donde almacenar el código de la moneda, ya que el título se va a usar como descripción del código de la moneda.

He de avisar que, para esta característica del precio del libro, se puede realizar directamente una columna de tipo Elección en el cual se define directamente los tipos de monedas. Hay que tener en cuenta, el interfaz de usuario del componente SPfx en la gestión de los libros, siendo más fácil acceder a la información de una lista, que a la definición de una columna.

Columnas de sitio

A la hora de definir una columna de sitio, hay que tener en cuenta el siguiente comportamiento de la caja de texto Nombre de la columna:

  • Cuando se crea la definición de la columna, el valor de la caja de texto funciona como nombre interno de la columna.

  • Cuando se modifica la definición de la columna, el valor de la caja de texto funciona como etiqueta que da nombre a la columna de la lista de cara al usuario final.

Además, se recomienda las siguientes pautas a la hora de definir el nombre interno de una columna personalizada.

  • El nombre no debe contener espacios en blanco para un mejor manejo de la columna en el desarrollo.

  • El nombre debería contener un prefino, para identificar mejor las columnas personalizadas de las columnas que ofrece por defecto SharePoint.

  • El nombre que se dé a la columna debe ser coherente con la funcionalidad de la columna.

Columna Código moneda

La columna que contendrá el código del formato del precio del libro dispondrá de las siguientes características:

Propiedades columna Valores columna

Nombre interno

LibCurrencyCode

Nombre

Currency code

Tipo de columna

Una sola línea de texto

Grupo

Book management

Requerido

Los demás opciones y configuraciones que no se han mencionado, se han dejado con los valores por defecto.

Tipo de contenido

El tipo de contenido que se va a aplicar a la lista que contendrá los tipos de monedas con la que posteriormente se registren los libros en SharePoint, tiene las siguientes características:

Propiedades tipo de contenido Valores tipo de contenido

Nombre

New type of currency

Descripción

Create a type of currency in the list

Tipo de contenido padre

Item

Grupo

Book management

Una vez creado el tipo de contenido, se procede a agregar las columnas personalizadas, que definirán la estructura de información que se utilizarán posteriormente en los repositorios de datos. Las columnas agregadas son las siguientes:

  • Currency code.

Ejemplo del tipo de contenido para los tipos de monedas

Definición de la lista

Las características de la lista personalizada, que contendrá los diferentes tipos de monedas son las siguientes:

  • Al crear la lista, se recomienda dar un nombre de lista sin espacios ni caracteres especiales. El motivo es que así se generará la lista con una url relativa más amigable a la hora de desarrollar componentes en SharePoint. Más adelante, se puede cambiar el título de la lista a un nombre con los espacios y caracteres especiales.

    La creación de la lista se va a realizar en la raíz de la colección se sitios, para poder ser accedida desde los subsitios de una forma óptima.

  • La lista solo contendrá el tipo de contenido personalizado que se ha creado previamente. En este ejercicio el nombre del tipo de contenido es New type of currency.

  • El tipo de contenido Elemento que viene por defecto al crear la lista, será eliminado.

  • En la lista, dejar la opción Permitir la administración de tipos de contenido desactivada, para evitar tener más campos innecesarios al crear o editar elementos en la lista.

  • En la lista, dejar la opción Permitir que esta lista aparezca en los resultados de búsqueda desactivada. Ya que por ahora no es necesario que los datos sean indexados por el buscador de SharePoint.

  • En la lista, dejar la opción Los datos adjuntos a los elementos de lista desactivada, para no insertar adjuntos en los elementos de la lista, por ser innecesarios.

  • En cuanto a la vista por defecto, se han realizado las siguientes características.

    • Se ha agregado la columna Currency code a la vista.

    • Se ha configurado los resultados de la vista por defecto, para ser devueltos ordenados alfabéticamente por el campo Título, para una mejor visualización del contenido.

Ejemplo de la lista que contienen los tipos de monedas

Definir el repositorio de almacenamiento de los libros

He de informar que, el repositorio de los libros registrados en SharePoint se va a realizar en una lista personalizada, ya que se va a dar más importancia a los datos del libro (Título, genero, precio, etc.…), que a la caratula del libro, que en caso de no tener se visualizará una caratula por defecto.

Columnas de sitio

Para almacenar la información relevante de los libros, es necesario crear nuevas columnas personalizas. También hay que destacar, que se va a reutilizar la columna Currency code ya que cumple el mismo propósito que se usaba para la lista de tipo de monedas.

Columna Precio

La columna que contendrá el precio del libro dispondrá de las siguientes características:

Propiedades columna Valores columna

Nombre interno

LibPrice

Nombre

Price

Tipo de columna

Moneda

Grupo

Book management

Requerido

Número de decimales

2

Valor por defecto

0

Formato de moneda

Formato Estados Unidos

Los demás opciones y configuraciones que no se han mencionado, se han dejado con los valores por defecto.

Columna Género

La columna que contendrá el tipo de genero al que pertenece el libro dispondrá de las siguientes características:

Propiedades columna Valores columna

Nombre interno

LibTypeGenre

Nombre

Genre

Tipo de columna

Una sola línea de texto

Grupo

Book management

Requerido

Los demás opciones y configuraciones que no se han mencionado, se han dejado con los valores por defecto.

Tipo de contenido

El tipo de contenido que se va a aplicar a la lista que contendrá los libros registrados en SharePoint, tiene las siguientes características:

Propiedades tipo de contenido Valores tipo de contenido

Nombre

New book

Descripción

Create a book in the list

Tipo de contenido padre

Item

Grupo

Book management

Una vez creado el tipo de contenido, se procede a agregar las columnas personalizadas, que definirán la estructura de información que se utilizarán posteriormente en los repositorios de datos. Las columnas agregadas son las siguientes:

  • Currency code.

  • Genre.

  • Price.

Ejemplo del tipo de contenido de los libros

Definición de la lista

Las características de la lista personalizada, que contendrá los registros de los libros son las siguientes:

  • Al crear la lista, se recomienda dar un nombre de lista sin espacios ni caracteres especiales. El motivo es que así se generará la lista con una url relativa más amigable a la hora de desarrollar componentes en SharePoint. Más adelante, se puede cambiar el título de la lista a un nombre con los espacios y caracteres especiales.

    La creación de la lista se va a realizar en la raíz de la colección se sitios, para poder ser accedida desde los subsitios de una forma óptima.

  • La lista solo contendrá el tipo de contenido personalizado que se ha creado previamente. En este ejercicio el nombre del tipo de contenido es New book.

  • El tipo de contenido Elemento que viene por defecto al crear la lista, será eliminado.

  • En la lista, dejar la opción Permitir la administración de tipos de contenido desactivada, para evitar tener más campos innecesarios al crear o editar elementos en la lista.

  • En la lista, en la sección de columnas indexadas, se ha agregado la columna Genre.

    Ejemplo de la configuración de una lista indexada

  • En cuanto a la vista por defecto, se han realizado las siguientes características.

    • Se ha agregado las columnas en el siguiente orden en la vista:

      • Genre.

      • Price.

      • Currency code.

    • Se ha configurado los resultados de la vista, para ser devueltos ordenados alfabéticamente por el campo Título, para una mejor visualización del contenido.

      En caso de haber dos títulos iguales, se van a ordenar por tipo de genero de libro.

Ejemplo de la lista que contienen los libros

Adaptar la plantilla de aprovisionamiento a las nuevas necesidades

Una vez que se tiene definido todos los elementos necesarios para la gestión de los libros dentro de la librería, se puede usar el mismo script de PowerShell para generar la plantilla que se utilizará para aprovisionar el entorno de producción.

Al ejecutar el script PnP-GetTemplateBookManagement.ps1 con los parámetros correspondientes, el XML generado es el siguiente:

Ejemplo del XML exportado para la plantilla de aprovisionamiento

De este fichero XML hay que destacar los siguientes aspectos:

  • En la versión anterior no existía la sección pnp:SiteFields, ya que no se habían definido columnas personalizadas para los tipos de géneros de libros.

    Como ahora ya se dispone de tres columnas personalizadas, se ha generado esta nueva sección con las columnas del grupo Book management.

    Quiero informar que, antes de redactar la entrada en el blog, al ejecutar el script, en esta sección, se había definido una columna de más, ajena al desarrollo del ejercicio, y que ahora no esta definida en el esquema. Puede ser debido a la actualización del SharePoint PnP.

  • En la sección pnp:ContentTypes con respecto a la versión anterior, se han agregado dos tipos de contenido nuevos, pertenecientes al grupo Book management.

  • En la sección pnp:Lists con respecto a la versión anterior, se han definido dos listas nuevas y a la vez han desaparecido la definición de otras listas que no son relevantes para el ejercicio.

He de informar que, a mi personalmente no me gusta tener plantillas de aprovisionamiento con más información que lo necesario. Ya que Microsoft puede realizar mantenimientos en las granjas y al aplicar definiciones de librerías propias de SharePoint, pero con una definición de una versión anterior, se puede perjudicar a la colección de sitio donde se aplique.

Estuve investigando como filtrar de una forma más exhaustivamente la información del XML que se genera con el comando Get-PnPProvisioningTemplate de SharePoint PnP. No encontré nada al respecto, pero si vi una página web que manipulaba el XML generado, para agregar más nodos de información.

Con este enfoque, decidí manipular el XML generado, para eliminar aquellas definiciones de elementos que no me son necesarias. Para este ejercicio, las definiciones que no se desean son las siguientes:

  • Todas las definiciones de columna que no pertenezcan al grupo Book management.

  • Todas las definiciones de lista, que no contengan tipos de contenidos pertenecientes al grupo Book management.

Teniendo en cuenta las nuevas premisas que debe cumplir el script PnP-GetTemplateBookManagement.ps1, su código queda de la siguiente manera:

#region Parameters
[CmdletBinding()]
Param(
    [Parameter(Mandatory = $True, Position = 1)]
    [ValidateNotNullOrEmpty()]
    [string]$SiteUrl,
    [Parameter(Mandatory = $True, Position = 2)]
    [ValidateNotNullOrEmpty()]
    [string]$UserName
)
#endregion

$location = Get-Location;
. ".\PnP-Utilities.ps1"
$ConstNameGroup = "Book management"

Write-Host "Process begins ..." -ForegroundColor DarkMagenta
$Context = Get-Context $SiteUrl $UserName    
if ($Context -ne $null){  
    Write-Host;
    Write-Host "Creating PnP Template ..." -ForegroundColor Yellow; 
    Get-PnPProvisioningTemplate -Out "$location\Templates\Export\TemplateBookManagement.xml" -Force -ContentTypeGroups $nameGroup -Handlers ContentTypes, Lists, Fields  
    Write-Host "PnP Template Created" -ForegroundColor Yellow;
    $saveChanges=$false;
    $templateXml = [xml][io.File]::ReadAllText("$location\Templates\Export\TemplateBookManagement.xml") 
    #region Delete fields
    Write-Host "Deleting fields that do not belong to the '$ConstNameGroup' group ..." -ForegroundColor Yellow;         
    $siteFieldsXML = $templateXml.Provisioning.Templates.ProvisioningTemplate.SiteFields
    if ($siteFieldsXML -ne $null){
        $fieldsDelete = New-Object System.Collections.Specialized.OrderedDictionary
        foreach($node in $siteFieldsXML.ChildNodes){
            $deleteThisField = $true;
            $theAttribute = $node.Attributes.GetNamedItem("Group")
            if (($theAttribute -ne $null) -and ([string]::Compare($ConstNameGroup, $theAttribute.Value, $true) -eq 0)){
                $deleteThisField = $false;
            }            
            if ($deleteThisField){
                $fieldsDelete.Add($node,$null);
            }
        }        
        foreach ($theField in $fieldsDelete.Keys){
            $saveChanges=$true;
            $siteFieldsXML.RemoveChild($theField);
        }
    }
    Write-Host "Deleted fields that do not belong to the '$ConstNameGroup' group" -ForegroundColor Yellow;
    #endregion

    #region Delete list
    Write-Host "Deleting lists that do not have the content type of the '$ConstNameGroup' group ..." -ForegroundColor Yellow;
    $contentTypesXML = $templateXml.Provisioning.Templates.ProvisioningTemplate.ContentTypes
    if ($contentTypesXML -ne $null){
        $listsDelete = New-Object System.Collections.Specialized.OrderedDictionary
        $contentTypesID = New-Object System.Collections.Specialized.OrderedDictionary
        foreach($node in $contentTypesXML.ChildNodes){
            $contentTypesID.Add($node.Attributes.GetNamedItem("ID").Value,$null)
        }
        $listsXML = $templateXml.Provisioning.Templates.ProvisioningTemplate.Lists
        if ($listsXML -ne $null){
            foreach($nodeList in $listsXML.ChildNodes){
                $deleteThisList = $true;
                foreach($nodeContentTypeBinding in $nodeList.ContentTypeBindings.ChildNodes){
                    if($contentTypesID.Contains($nodeContentTypeBinding.Attributes.GetNamedItem("ContentTypeID").Value)){
                        $deleteThisList = $false;
                        break;
                    }
                }
                if ($deleteThisList){
                    $listsDelete.Add($nodeList,$null);
                }
            }
        }
        foreach ($theList in $listsDelete.Keys){
            $saveChanges=$true;
            $listsXML.RemoveChild($theList);            
        }
    }
    Write-Host "Deleted lists that do not have the content type of the '$ConstNameGroup' group" -ForegroundColor Yellow;
    #endregion

    if ($saveChanges){
        $templateXml.Save("$location\Templates\Export\TemplateBookManagement.xml");
    }
 Write-Host;
}
Write-Host "Process finished" -ForegroundColor DarkMagenta

Hay que recordar que, este script de Powershell, utiliza el script PnP-Utilities.ps1, que dispone de una serie de utilidades para trabajar con SharePoint PnP.

Al ejecutar de nuevo el script la plantilla de aprovisionamiento quedaría de la siguiente forma:

Ejemplo del XML exportado para la plantilla de aprovisionamiento

Importar plantilla de aprovisionamiento

Una vez que se tiene definido XML de aprovisionamiento que se va a utilizar para actualizar el entorno de producción, se ejecuta el script PnP-ApplyTemplate.ps1 con los parámetros correspondientes.

Ejemplo de la plantilla de aprovisionamiento para aplicar en otro entorno

Una vez finalizado el proceso del script, se podrá comprobar que se han creado las nuevas columnas personalizadas, los tipos de contenidos y las listas según el esquema de aprovisionamiento proporcionado.

Comprobación que se han creado las columnas, tipos de contenido y listas en el entorno de producción

Columna Genre indexada

Quiero informar que, mientras estaba revisando los elementos creados en el entorno de producción a partir de la plantilla de aprovisionamiento, me di cuenta de que, la lista Books no contenía la columna indexada definida en el entorno de desarrollo.

Estuve revisando la documentación del proceso de generar la plantilla de aprovisionamiento, sobre las columnas que se pueden indexar en las definiciones de lista y no encontré nada al respecto. Realicé unas pruebas sobre la plantilla de aprovisionamiento y descubrí que, si en la definición de la columna personalizada Genre se configura la propiedad Indexed, el cambio se ve reflejado en la lista Books automáticamente al volver a lanzar el proceso de importación de la plantilla de aprovisionamiento.

Como se quiere que los procesos de generación de la plantilla de aprovisionamiento sean lo más automatizados posibles y teniendo en cuenta que la propiedad Indexed no se puede configurar a nivel de interfaz grafico desde SharePoint, de ha desarrollado el script que modifica dicha propiedad. A continuación, se describe las características del script PnP-UpdateIndexPropertyField.ps1:

  • El script tiene tres parámetros obligatorios para su ejecución.

    • SiteUrl: Url de la colección de sitios de donde se va a realizar la operativa.

    • UserName: Usuario con el que se va a conectar a la colección de sitios.

    • Identity: Indica el nombre interno de la columna personalizada que se quiere cambiar el valor de la propiedad Indexed.

  • El script usar el script PnP-Utilities.ps1, que dispone de una serie de utilidades PnP para trabajar con SharePoint.

#region Parameters
[CmdletBinding()]
Param(
    [Parameter(Mandatory = $True, Position = 1)]
    [ValidateNotNullOrEmpty()]
    [string]$SiteUrl,
    [Parameter(Mandatory = $True, Position = 2)]
    [ValidateNotNullOrEmpty()]
    [string]$UserName,
 [Parameter(Mandatory = $True, Position = 3)]
    [ValidateNotNullOrEmpty()]
    [string]$Identity  
)
#endregion
. ".\PnP-Utilities.ps1"

Write-Host "Process begins ..." -ForegroundColor DarkMagenta

$Context = Get-Context $SiteUrl $UserName    
if ($Context -ne $null){  
    Write-Host;
    Write-Host "Updating field ..." -ForegroundColor Yellow;   
    $result = Get-PnPField -Identity $Identity -ErrorAction SilentlyContinue
    if ($result -ne $null){
        if ($result.Indexed -eq $false){
            Set-PnPField -Identity $Identity -Values @{Indexed=$True} -UpdateExistingLists
        }
        else{            
            Write-Host "The field '$Identity' has already been updated" -ForegroundColor Green;
        }
    }
    else{
        Write-Host "Field '$Identity' not found" -ForegroundColor Red;
    }
    Write-Host "Updated field" -ForegroundColor Yellow;
    Write-Host;
}
Write-Host "Process finished" -ForegroundColor DarkMagenta

Con el script definido, estos son los pasos a realizar para disponer de la indexación de la columna Genre en la lista Books del entorno de producción:

  1. Ejecutar el script PnP-UpdateIndexPropertyField.ps1 para cambiar la propiedad de indexación de la columna Genre.

  2. Volver a ejecutar el script PnP-GetTemplateBookManagement.ps1 para obtener la nueva definición de la plantilla de aprovisionamiento.

  3. Volver a ejecutar el script PnP-ApplyTemplate.ps1 para reflejar los cambios en el entono de producción.

Aprovisionar entorno con datos en una lista y otros recursos

Una vez que se tienen las listas definidas en el entorno de producción, se va a proceder a cargar en las listas aquella información que no estuviera previamente.

A su vez, se va a configurar en el esquema de aprovisionamiento de datos, la subida de un fichero de tipo imagen a la biblioteca de estilos, para disponer de imagen por defecto en las caratulas de los libros.

He de recordar que, en la definición de la lista para los tipos de géneros de libros, ya se cargó la lista con datos, así que, en esta segunda ejecución de datos, solo debería de subir los datos nuevos, si hubiera.

Hay que avisar que, si la definición de la lista de tipos de géneros de libros hubiera sufrido algún cambio durante los desarrollos, es importante actualizar en el esquema de aprovisionamiento su definición, para evitar los problemas futuros.

Ejemplo del esquema de aprovisionamiento de datos y recursos de la gestión de los libros

Del nuevo esquema de aprovisionamiento se destaca los siguientes aspectos:

  • Se ha definido una nueva lista a aprovisionar Type of currency y se ha agregado los datos que se quiere cargar en la lista.

  • Se ha agregado la sección pnp:Files donde se definen los ficheros que se van a subir a la biblioteca de estilos.

    He de informar que, los ficheros de cargan en SharePoint, se han colocado en una estructura de carpetas en el mismo directorio donde se encuentra el esquema de aprovisionamiento de datos.

Ejecutar el script PnP-ApplyTemplate.ps1 con los parámetros correspondientes e indicando la plantilla de aprovisionamiento de datos. Tras su finalización se puede comprobar que se dispone de la información cargada en listas y repositorios de imágenes.

Entradas populares de este blog

Cargar archivos desde PowerApps a bibliotecas de SharePoint

Menús desplegables relacionados en SharePoint Online

Gestionar excepciones en Power Automate