Ahora, esto llega a generar cierta confusión en ellos cuando se adentran al detalle de la nota en la que pone las diferencias entre la plataforma en la nube (es decir SharePoint Online) y la plataforma On-Premise (dentro de nuestra infraestructura de servidores); y es completamente normal; como normal es que yo no conozca a profundidad de leyes, contabilidad, marketing, microbiología, etc. Para esos casos en los que necesitas entender o resolver esos pequeños-grandes detalles, siempre lo recomendable es acudir con un experto.
Pues bien, en esta ocasión les comparto mi experiencia con este requerimiento que a mi parecer es muy normal, sobre todo, saber quién ha leído un documento dentro de SharePoint Online (que al momento de escribir este post, no permite auditar las descargas o las lecturas de documentos en la plataforma de manera natural). Para exponer el caso tomemos en cuenta lo siguiente:
- SharePoint es una plataforma flexible que permite crear tantos sitios web como bibliotecas de documentos tengamos en mente. El orden o estructura se lo podemos dejar a la imaginación, por lo que la solución que demos, debe ser tan flexible como bibliotecas tengamos.
- Los usuarios que gestionan el contenido en los sitios quieren saber qué usuarios acceden al contenido que ellos publican en los diversos portales.
- Se espera que los documentos sean compartidos en diferentes formas como:
- Vínculos mediante correo electrónico.
- Colocando los vínculos en los menús o portales como accesos directos.
Trasladando esta observación a nuestro escenario, ¿podríamos nosotros proponer una pequeña App que modifique los vínculos de los documentos y que, éstos vínculos nos permitan enviar a los usuarios que los presionen a una página intermedia que registre el comportamiento?
Claro que sí y para ello, habría que crear un proyecto en Visual Studio con la plantilla de SharePoint Add-In.
Para ello:
2. Agregué una página web llamada Analytics.aspx
3. Agregué un nuevo ítem del estilo Menu Item Custom Action al que llamé GetURLAudit y seleccioné la página creada en el punto 1.
Agregando el Control para el menú |
4. Este ítem te permite asociarlo a tipos de contenido Biblioteca de documentos e indicar que se presentará en las bibliotecas de documentos del sitio Host.
Asignando en dónde se mostrará el nuevo control |
Indicando la página que se mostrará al presionar el botón. |
Si observamos un poco el XML creado por el ítem, éste nos indica que proporcionará como parámetro en la URL el ID de la lista y el ID del ítem con lo que podremos recuperar (usando un poco de programación con JavaScript) toda la información del documento.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction Id="8c10803a-8293-427b-84b1-250036b46c18.GetURLAudit"
RegistrationType="List"
RegistrationId="101"
Location="EditControlBlock"
Sequence="10001"
Title="Obtener URL Auditable">
<UrlAction Url="~appWebUrl/Pages/URLAuditable.aspx?{StandardTokens}&SPListItemId={ItemId}&SPListId={ListId}" />
</CustomAction>
</Elements>
5. En la página a la que nos referencía construiremos la URL que nos ayudará a capturar el comportamiento de los visitantes. Para ello, agregué en la página un campo de texto.
Campo de texto para construir una URL |
6. Cree una lista de SharePoint llamada Registro en la que capturaré todos los eventos de carga de la página Analytics.aspx.
Agregando la lista para registrar las visitas. |
7. En la página ULAuditable.aspx coloqué el siguiente código jQuery para generar la nueva liga:
var hostweburl;
var appweburl;
var idLista;
$(document).ready(function () {
hostweburl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
appweburl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));
var scriptbase = hostweburl + "/_layouts/15/";
$.getScript(scriptbase + "SP.RequestExecutor.js", getListName);
});
function getListName() {
var executor = new SP.RequestExecutor(appweburl);
idLista = decodeURIComponent(getQueryStringParameter("SPListId")).replace("{", "").replace("}", "");
executor.executeAsync(
{
url: appweburl + "/_api/SP.AppContextSite(@target)/web/lists(guid'" + idLista + "')?@target='" + hostweburl + "'",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
var jsonObject = JSON.parse(data.body);
var tituloBiblioteca = jsonObject.d.Title;
getDocumentName(tituloBiblioteca);
},
error: onQueryFailed
}
);
}
function getDocumentName(tituloBiblioteca) {
var executor = new SP.RequestExecutor(appweburl);
var iditem = decodeURIComponent(getQueryStringParameter("SPListItemId")).replace("{", "").replace("}", "");
executor.executeAsync(
{
url: appweburl + "/_api/SP.AppContextSite(@target)/web/lists/GetByTitle('" + tituloBiblioteca + "')/items(" + iditem + ")/File?@target='" + hostweburl + "'",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
var jsonObject = JSON.parse(data.body);
$("#txtURLEditable").val(appweburl + "/Pages/Analytics.aspx?SPHostUrl=" + encodeURIComponent(hostweburl) + "&SPAppWebUrl=" + encodeURIComponent(appweburl) + "&SPListId=" + encodeURIComponent("{" + idLista + "}") + "&SPListItemId=" + iditem);
},
error: onQueryFailed
}
);
}
var hostweburl;
var appweburl;
var idLista;
var context, web;
$(document).ready(function () {
context = SP.ClientContext.get_current();
web = context.get_web();
context.load(web);
context.executeQueryAsync((this, function (sender, args) {
getListName();
}),
Function.createDelegate(this, onQueryFailed));
});
function getListName() {
var executor = new SP.RequestExecutor(appweburl);
idLista = decodeURIComponent(getQueryStringParameter("SPListId")).replace("{", "").replace("}", "");
executor.executeAsync(
{
url: appweburl + "/_api/SP.AppContextSite(@target)/web/lists(guid'" + idLista + "')?@target='" + hostweburl + "'",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
var jsonObject = JSON.parse(data.body);
var tituloBiblioteca = jsonObject.d.Title;
getDocumentName(tituloBiblioteca);
},
error: onQueryFailed
}
);
}
function getDocumentName(tituloBiblioteca) {
var executor = new SP.RequestExecutor(appweburl);
var iditem = decodeURIComponent(getQueryStringParameter("SPListItemId")).replace("{", "").replace("}", "");
executor.executeAsync(
{
url: appweburl + "/_api/SP.AppContextSite(@target)/web/lists/GetByTitle('" + tituloBiblioteca + "')/items(" + iditem + ")/File?@target='" + hostweburl + "'",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
var jsonObject = JSON.parse(data.body);
registrarEvento(jsonObject.d.Name, tituloBiblioteca, jsonObject.d.LinkingUrl);
},
error: onQueryFailed
}
);
}
function registrarEvento(nombreArchivo, tituloBiblioteca, url) {
var oList = context.get_web().get_lists().getByTitle('Registro');
var itemCreateInfo = new SP.ListItemCreationInformation();
var oListItem = oList.addItem(itemCreateInfo);
oListItem.set_item('Title', nombreArchivo);
oListItem.set_item('Biblioteca', tituloBiblioteca);
oListItem.update();
context.load(oListItem);
context.executeQueryAsync(
Function.createDelegate(this, function (sender, args) {
console.log("Evento registrado");
window.location = url;
}),
Function.createDelegate(this, onQueryFailed));
}
Si observan el código, es muy similar al del punto 7 y puede haber algunas cosas que no sean necesarias debido a que es un ejemplo recortado del requerimiento original, en el que nos pidieron leer propiedades adicionales del usuarios como su número de Empleado y su Puesto. Sin embargo, creo que funciona bien para los propósitos del post.
9. Le di permisos de lectura al App desde el archivo Manifest.xml a la colección de sitios y los perfiles de usuarios (este último por si haces lectura desde los perfiles de usuario para traer información adicional).
10. ¡Finalmente, a probar!
Una vez corriendo la aplicación, todas las bibliotecas de documentos en el sitio Host tendrán un nuevo control que nos permitirá crear la URL, compartirla y al abrirla, registrar el evento de lectura.
Control en biblioteca de SharePoint Online |
Registro de auditoría en la lista personalizada dentro del App. |
¡Espero que este post les sea de utilidad y de ser así, por favor compartan y comenten que estamos para escucharlos!
También están invitados a conocer Chimalli Apps en donde colocamos soluciones empresariales para ustedes.
No hay comentarios:
Publicar un comentario