lunes, 24 de marzo de 2014

SP2013: Cómo simular permisos a nivel de campo (columna) de lista mediante 2 listas relacionadas

Que quede claro desde el principio: En SharePoint (2013 y anteriores) no se puede hacer una configuración de permisos a nivel de campo (columna/metadato) en una lista o biblioteca de forma out of the box. El más bajo nivel de granularidad de permisos está a nivel de ítem o documento. Hasta donde humildemente sé, Microsoft no ofrece este nivel de permisos para evitar que el rendimiento de la plataforma se vea afectado (no comments...)

Para simular este comportamiento, se puede recurrir a diversas soluciones adicionales, tales como:
  • Formularios personalizados: InfoPath, custom .aspx, Nintex Forms...
  • Fabricarse con Visual Studio y código .NET un tipo de control en listas que permita especificar permisos.

Personalmente no soy amigo de ninguna de ellas, debido a los problemas que el custom code puede suponer en futuras migraciones. En relación a InfoPath, ya sabemos todos que le han hecho un funeral propio en la SharePoint Conference 2014, y que en cuestión de un año aproximadamente se empezará a recibir una tecnología sustitutiva (recemos para que incorpore lógica de campos en sus primeras versiones).

Así que hoy me voy a centrar en otro tipo de solución para "simular" (no es realmente así) el comportamiento de "permisos a nivel de campo de lista". Es cierto que no os servirá para todos los casos, ni para las casuísticas más complejas que requieran de múltiples estados, pasos o campos, pero estoy seguro de que, como a mí, os podrá alegrar el día en más de una ocasión.

Imaginemos el siguiente requerimiento de cliente: Quiero tener un listado de tareas (tipo Project professional) con múltiples campos, pero el usuario solo ha de poder modificar uno de ellos.

Lo primero que de forma natural nos vendrá a la cabeza es que SharePoint no permite "que el usuario solo pueda modificar uno de ellos", la configuración de seguridad se deja hacer a nivel de lista o de ítem, no de metadato. Es cierto que podríamos jugar con aspectos como la configuración de las vistas, o limitar la edición de algunos campos para que en los formularios no fueran visibles, pero seguramente al cliente no le satisfacería ninguna de ellas, por la carencia de una seguridad real (las vistas capadas se podrían saltar si el usuario conoce la URL de la vista "completa") o por los posibles efectos secundarios de las mismas (si configuras que un campo se oculte en los formularios, tampoco se mostrará en el momento que lo necesites informar para su alta).

Así pues, la solución propuesta es la de disponer de 2 listas distintas: Una para el usuario que crea la información, otra para el usuario que la modifica, y vincularlas mediante campos de tipo "lookup" y un sencillo flujo de trabajo. El esquema de funcionamiento sería el siguiente:

 
Vamos por pasos:

1.- Crear la lista original (que he llamado "Project Tasks"), con todos los campos de información que el usuario creador de contenidos ha de poder informar. Esta "custom list" la crearemos de forma totalmente normal, con sus campos de tipo "single line of text", "Number", "Date and Time"... En mi caso tiene un aspecto como el siguiente:



2.-Crear la lista destino (que he llamado "User Tasks"). En este caso también será una "Custom list", pero sólo crearemos de forma "normal" los campos que el usuario deba poder modificar. En mi caso era un único campo, "New Remaining Duration". El resto de campos los importaremos de la lista anterior mediante un campo de tipo lookup vinculado a la primera lista. El campo principal será el nombre de la tarea, pero luego añadiremos todos los campos que queremos que el usuario pueda ver (pero no modificar).

 
3.- A continuación, en esta segunda lista, iremos a su configuración avanzada (list settings --> Advanced Settings) y marcaremos que permita la gestión de los tipos de contenido en la lista

 
 
4.- A continuación, iremos a la pantalla de edición del content type de la lista, desde la pantalla de "list settings" (sección "Content Types").


5.- Ocultaremos todos los campos que no queramos que aparezcan en los formularios de edición del ítem, como la propia columna que vincula con la primera lista (tasks), debido a que ya crearemos un workflow que se encargue de generar automáticamente los ítems en la segunda lista. Para ello, pulsaremos en los nombres de las columnas que queramos ocultar, y en la pantalla de detalles del campo, pulsaremos en la opción "This column is: Hidden (Will not appear in forms)".


En mi caso oculté las columnas "Title", "Task" y alguna otra que creé específicamente para la gestión de permisos de los ítems. Dejé únicamente como "Optional" la columna que sí quería que el usuario pudiera modificar.


Llegados a este punto, si intentamos crear un nuevo ítem en la segunda lista, veremos que, efectivamente, SharePoint solo nos pregunta por el campo que hemos dejado visible en el content type.

6.- Ahora ya solo nos falta crear, en la lista original, un sencillo workflow de SharePoint 2013 que, cada vez que se cree un nuevo elemento en la lista principal, copie el ítem en la segunda lista. El workflow, en mi caso, consta de los siguientes pasos:
  1. Acción para fijar el estado del flujo inicialmente ("Set Workflow Status" en "Core Actions")
  2. Acción para notificar en el log del flujo que el flujo ha comenzado correctamente ("Log to History List" en "Core Actions")
  3. Acción que para crear el ítem en la segunda lista, basándonos en todos los valores que contiene la primera ("Create List Ítem" en "List Actions")
  4. Acción para notificar en el log del flujo que el flujo ha finalizado ("Log to History List" en "Core Actions")
  5. Acción para fijar el estado del flujo inicialmente ("Set Workflow Status" en "Core Actions")
Destacar que la acción número 3, la de copiar el ítem de la 2a a la primera lista, el campo principal a informar es el que creamos como base del lookup ("task" en mi ejemplo) y que aunque al final veamos un valor de tipo string escrito en él, en realidad, le tenemos que pasar el ID del elemento actual que está ejecutando el flujo. Es importante el detalle de escribir el ID en lugar del campo "task", porque el lookup espera un campo de tipo integer (ID del elemento origen) y no un string, y hacerlo de otra forma provocaría error en el flujo.


Así pues, el flujo debería tener un aspecto similar al de la siguiente imagen.

 
 
Ya está todo hecho. Veremos que si el usuario "creador" introduce en ítems en la primera lista, estos se copian a la segunda, donde el usuario "informador", o "editor" podrá ver todos los datos, pero editar únicamente los que creamos explícitamente a tal efecto y dejamos visibles en la configuración del content type de la lista.

Se podría complicar la casuística, añadiendo más fases de edición (más listas) y reflujos de retorno (que al modificar algo en la segunda lista, copiara los cambios en la 1a, por ejemplo), pero esto ya dependerá de los requerimientos de cada cliente y aquí cada uno evolucionará el modelo según la necesidad de cumplir dichos requerimientos.

Realmente no es una forma sencilla ni "bonita" de trabajar, pero podemos cumplir con lo de "que unos usuarios puedan editar unos campos y otros usuarios editen otros campos" sin programar una sola línea de código.

Personalmente rezo para que lleguen pronto los prometidos FoSL (Evolución natural de los List Forms), y que permitan realizar, con una interface intuitiva integrada en la gestión de las listas, lo que ahora teníamos que configurar en InfoPath, Visual Studio .NET u otros programas de formularios SharePoint de terceros.

Hasta entonces...¡¡Ahí queda eso!!

2 comentarios:

Anónimo dijo...

¿Cuándo te refieres un campo tipo "lookup", como está traducido en SharePoint en castellano?

Gracias.

Ignasi Tebé Tena dijo...

Buenas, la traducción en español es un campo de tipo "búsqueda".

¡Un saludo!