SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (V)

Entradas anteriores de la serie:

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (I)

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (II)

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (III)

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (IV)


bender2

Después de algunos días sin poder seguir con la serie porque han detenido a Bender hay que sacar adelante otros proyectos, volvemos a la carga con lo que promete ser la serie de artículos más larga que he publicado hasta ahora en este blog.

 

Antes de nada vamos a ponernos al día:

Que pretendemos?

Crear un add-in de Outlook que permita guardar nuestros correos en una librería de documentos de SharePoint (tanto MOSS como WSS).

Que necesitamos?

  • Cómo crear un complemento para Office (VSTO). visto
  • Cómo registrar acciones en los menús de la aplicación host (Outlook). visto
  • Cómo conectar con un servidor MOSS/WSS con diferentes credenciales de usuario (System.Net.NetworkCredential) visto
  • Cómo acceder a los sitios y listas de un site de MOSS/WSS (servicios Web de SharePoint). visto
  • Cómo interpretar la información XML devuelta por los servicios (LINQ to XML). visto
  • Cómo extender el modelo de objetos de SharePoint para acceder los valores devueltos por los servicios Web.
  • Cómo crear las columnas necesarias en una lista para guardar los metadatos del elementos de correo (From, To, Subject).
  • Cómo guardar un fichero en una biblioteca de documentos de SharePoint con control de versiones (DocLibHelper).
  • Cómo ejecutar distintos threads y mostrar el progreso (Callbacks).
  • Cómo distribuir nuestro complemento, creando un archivo MSI (Windows Installer packages).

Que vamos a ver hoy?

En este post vamos a centrarnos en cómo obtener datos de los servicios Web de SharePoint. En nuestro caso necesitamos obtener las colecciones de sitios, las librerías de cada uno de los sitios, y las carpetas de cada librería para mostrarlos en una ventana que permita al usuario seleccionar la ubicación en la que desea guardar los elementos de coreo:

AddIn_Step2

Del mismo modo, vamos a necesitar obtener las columnas de la librería seleccionada, para comprobar si ya existen las columnas para almacenar los metadatos de los elementos de correo, y en caso contrario proceder a crearlas (esto va a ir muy bien para posteriormente poder clasificar los elementos).

Correos1

 

Extendiendo el modelo de objetos de SharePoint

En el post anterior ya vimos que habíamos declarado algunas clases de apoyo (como la clase ‘SPSiteInfo’) para que nuestros métodos (como el método ‘getSiteSubSites’ que también vimos en el anterior post) pudiesen devolver colecciones genéricas de éestos tipos de datos, lo cual es mucho más manejable que pelearnos con el XML que devuelven los servicios Web de SharePoint.

Los métodos que vamos a crear son:

  • getSiteSubSites: Devuelve una lista genérica de objetos ‘SPSiteInfo’, a partir de un servicio Web websProxy.Webs
  • getSiteLists: Devuelve una lista genérica de objetos ‘SPListInfo’, a partir de un servicio Web listsProxy.Lists
  • getListFolders: Devuelve una lista genérica de objetos ‘SPFolderInfo’, a partir de un servicio Web listsProxy.Lists
  • getListColumns: Devuelve una lista genérica de objetos ‘SPFolderInfo’, a partir de un servicio Web listsProxy.Lists y de un listID (GUID)
  • createMetadataColumns: Crea las columnas de metadatos definidas en los settings del add-in en una lista, a partir de un servicio Web listsProxy.Lists y de un listID (GUID).

Las clases de apoyo son:

public class SPSiteInfo
{
    public string Title { get; set; }
    public string URL { get; set; }
 
    public SPSiteInfo()
    {
        //
    }
 
    public SPSiteInfo(string title, string url)
    {
        Title = title;
        URL = url;
    }
}
 
public class SPListInfo
{
    public Guid ID { get; set; }
    public string Title { get; set; }
    public string URL { get; set; }
 
    public SPListInfo()
    {
        //
    }
 
    public SPListInfo(Guid id, string title, string url)
    {
        ID = id;
        Title = title;
        URL = url;
    }
}
 
public class SPFolderInfo
{
    public string Title { get; set; }
    public string URL { get; set; }
 
    public SPFolderInfo()
    {
        //
    }
 
    public SPFolderInfo(string title, string url)
    {
        Title = title;
        URL = url;
    }
}
 
public class SPColumnInfo
{
    public string ID { get; set; }
    public string Type { get; set; }
    public string DisplayName { get; set; }
    public string Name { get; set; }
    public bool Hidden { get; set; }
    public bool Sealed { get; set; }
    public bool ReadOnly { get; set; }
 
    public SPColumnInfo()
    {
        //
    }
 
    public SPColumnInfo(string id, string type,
        string displayName, string name, bool hidden, 
        bool issealed, bool isreadonly)
    {
        ID = id;
        Type = type;
        DisplayName = displayName;
        Name = name;
        Hidden = hidden;
        Sealed = issealed;
        ReadOnly = isreadonly;
    }
}

Y el código de los métodos será el siguiente:

public class SharePointExtensions
{
    public static List<SPSiteInfo> getSiteSubSites(websProxy.Webs sharePointWebs)
    {
        try
        {
            XmlNode websResult = sharePointWebs.GetWebCollection();
            XDocument results = XDocument.Parse(websResult.OuterXml);
            XName name = XName.Get("Web", "http://schemas.microsoft.com/sharepoint/soap/");
            var webs = from item in results.Descendants(name)
                       select new SPSiteInfo
                           (
                           item.Attribute("Title").Value,
                           item.Attribute("Url").Value
                           );
            return webs.ToList();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
 
    public static List<SPListInfo> getSiteLists(listsProxy.Lists sharePointLists)
    {
        try
        {
            XmlNode listsResult = sharePointLists.GetListCollection();
            XDocument results = XDocument.Parse(listsResult.OuterXml);
            XName name = XName.Get("List", "http://schemas.microsoft.com/sharepoint/soap/");
            var lists = from item in results.Descendants(name)
                        where item.Attribute("ServerTemplate").Value.ToString() ==
                            Properties.Settings.Default.SERVER_TEMPLATE
                        select new SPListInfo
                            (
                            new Guid(item.Attribute("ID").Value),
                            item.Attribute("Title").Value,
                            item.Attribute("DefaultViewUrl").Value
                            );
            return lists.ToList();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
 
    public static List<SPFolderInfo> getListFolders(listsProxy.Lists sharePointLists, 
        string listName, string listText, string folderURL)
    {
        try
        {
            XmlDocument xmlDoc = new System.Xml.XmlDocument();
            XmlNode ndQuery = xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
            XmlNode ndViewFields =
              xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
 
            XmlNode ndQueryOptions = null;
            if (listName != folderURL)
            {
                ndQueryOptions = xmlDoc.CreateNode(
                    XmlNodeType.Element, "QueryOptions", "");
                ndQueryOptions.InnerXml = string.Format(
                    "<Folder>{0}/{1}</Folder>", listName, folderURL);
            }
 
            XName name = XName.Get("data", "urn:schemas-microsoft-com:rowset");
            XmlNode ndListItems =
                    sharePointLists.GetListItems(listText, null, ndQuery,
                    ndViewFields, null, ndQueryOptions, null);
            XDocument results = XDocument.Parse(ndListItems.OuterXml);
 
            var folders = from item in results.Descendants(name).Elements()
                          where item.Attribute("ows_ContentType").Value == "Carpeta"
                          select new SPFolderInfo
                             (
                             item.Attribute("ows_BaseName").Value,
                             item.Attribute("ows_ServerUrl").Value
                             );
            return folders.ToList();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
    
    public static List<SPColumnInfo> getListColumns(listsProxy.Lists sharePointLists, string siteID)
    {
        try
        {
            List<SPColumnInfo> columns =new List<SPColumnInfo>();
            XmlNode listsResult = sharePointLists.GetList(siteID);
            XDocument results = XDocument.Parse(listsResult.OuterXml);
            XName name = XName.Get("Field", "http://schemas.microsoft.com/sharepoint/soap/");
            var lists = from item in results.Descendants(name)
                        select item;
            foreach (var item in lists.ToList())
            {
                XAttribute aID = item.Attribute("ID");
                XAttribute aType = item.Attribute("Type");
                XAttribute aDisplayName = item.Attribute("DisplayName");
                XAttribute aName = item.Attribute("Name");
                XAttribute aHidden = item.Attribute("Hidden");
                XAttribute aSealed = item.Attribute("Sealed");
                XAttribute aReadOnly = item.Attribute("ReadOnly");
 
                if (aID != null && aType != null && aDisplayName != null &&
                    aName != null)
                {
                    bool ishidden = false;
                    bool issealed = false;
                    bool isreadonly = false;
                    if (aHidden != null && aHidden.Value.ToString() == "TRUE") ishidden = true;
                    if (aSealed != null && aSealed.Value.ToString() == "TRUE") issealed = true;
                    if (aReadOnly != null && aReadOnly.Value.ToString() == "TRUE") isreadonly = true;
                    columns.Add(new SPColumnInfo(
                        aID.Value.ToString(),
                        aType.Value.ToString(),
                        aDisplayName.Value.ToString(),
                        aName.Value.ToString(),
                        ishidden, issealed, isreadonly));
                }
            }
            return columns;
        }
        catch (Exception ex)
        {                
            throw ex;
        }
    }
 
    public static void createMetadataColumns(listsProxy.Lists sharePointLists, string listID)
    {
        int createColumnsCount = 0;
        if (!Properties.Settings.Default.OPTION_CREATE_METADATA_COLUMNS) return;
        var cols = from c in SharePointExtensions.getListColumns(
                   sharePointLists, listID)
                   where c.Hidden == false && c.Sealed == false && c.ReadOnly == false
                   select c;
 
        Dictionary<string, SPColumnInfo> columns = cols.ToDictionary(c => c.Name);
        string newFieldsList = "";
 
        if (!columns.ContainsKey(Properties.Settings.Default.COL_SUBJECT))
        {
            string subjectfield =
                @"<Method ID='1'><Field Type='Text' DisplayName='{0}' MaxLength='255'/></Method>";
            newFieldsList += string.Format(subjectfield, Properties.Settings.Default.COL_SUBJECT);
            createColumnsCount++;
        }
        if (!columns.ContainsKey(Properties.Settings.Default.COL_TO))
        {
            string subjectfield =
                @"<Method ID='2'><Field Type='Text' DisplayName='{0}' MaxLength='255'/></Method>";
            newFieldsList += string.Format(subjectfield, Properties.Settings.Default.COL_TO);
            createColumnsCount++;
        }
        if (!columns.ContainsKey(Properties.Settings.Default.COL_CC))
        {
            string subjectfield =
                @"<Method ID='3'><Field Type='Text' DisplayName='{0}' MaxLength='255'/></Method>";
            newFieldsList += string.Format(subjectfield, Properties.Settings.Default.COL_CC);
            createColumnsCount++;
        }
        if (!columns.ContainsKey(Properties.Settings.Default.COL_BCC))
        {
            string subjectfield =
                @"<Method ID='4'><Field Type='Text' DisplayName='{0}' MaxLength='255'/></Method>";
            newFieldsList += string.Format(subjectfield, Properties.Settings.Default.COL_BCC);
            createColumnsCount++;
        }
        if (!columns.ContainsKey(Properties.Settings.Default.COL_FROM))
        {
            string subjectfield =
                @"<Method ID='5'><Field Type='Text' DisplayName='{0}' MaxLength='255'/></Method>";
            newFieldsList += string.Format(subjectfield, Properties.Settings.Default.COL_FROM);
            createColumnsCount++;
        }
        if (!columns.ContainsKey(Properties.Settings.Default.COL_SENT))
        {
            string subjectfield =
                @"<Method ID='6'><Field Type='DateTime' DateOnly='FALSE' DisplayName='{0}'/></Method>";
            newFieldsList += string.Format(subjectfield, Properties.Settings.Default.COL_SENT);
            createColumnsCount++;
        }
        if (!columns.ContainsKey(Properties.Settings.Default.COL_SIZE))
        {
            string subjectfield =
                @"<Method ID='7'><Field Type='Number' DisplayName='{0}'/></Method>";
            newFieldsList += string.Format(subjectfield, Properties.Settings.Default.COL_SIZE);
            createColumnsCount++;
        }
        if (!columns.ContainsKey(Properties.Settings.Default.COL_IMPORTANCE))
        {
            string subjectfield =
                @"<Method ID='8'><Field Type='Choice' DisplayName='{0}'>;
                  <Default>{1}</Default>
                  <CHOICES>
                    <CHOICE>{2}</CHOICE>
                    <CHOICE>{3}</CHOICE>
                    <CHOICE>{4}</CHOICE>
                  </CHOICES>
                </Field></Method>"
            newFieldsList += string.Format(subjectfield,
                Properties.Settings.Default.COL_IMPORTANCE,
                Properties.Settings.Default.COL_IMPORTANCE_MEDIUM,
                Properties.Settings.Default.COL_IMPORTANCE_HIGH,
                Properties.Settings.Default.COL_IMPORTANCE_MEDIUM,
                Properties.Settings.Default.COL_IMPORTANCE_LOW);
            createColumnsCount++;
        }
        if (createColumnsCount > 0)
        {
            XmlNode ndList = sharePointLists.GetList(listID);
            XmlNode ndVersion = ndList.Attributes["Version"];
            XmlDocument xmlDoc = new System.Xml.XmlDocument();
            XmlNode ndNewFields = xmlDoc.CreateNode(XmlNodeType.Element, "Fields", "");
            ndNewFields.InnerXml = newFieldsList;
            try
            {
                XmlNode ndReturn =
                   sharePointLists.UpdateList(listID,
                   null, ndNewFields, null, null,
                   ndVersion.Value);
            }
            catch (Exception ex)
            {
 
                throw ex;
            }
        }
    }
}

Y con esto ya estamos en disposición de mostrar un cuadro de diálogo al usuario, para que seleccione la ubicación en el servidor de SharePoint dónde quiere guardar los elementos de correo.

En el próximo post veremos cómo guardar los elementos de corro en la ubicación seleccionada, creando las columnas de metadatos (si así lo hemos definido), y actualizando el valor de éstas columnas para guardar los valores de los campos de correo (Asunto, De, Para, Fecha, Tamaño, etc.).

Os recuerdo que al terminar la serie publicaré la solución con el código completo, por si a alguien le sirve.

Espero no demorarme tanto en escribir el próximo post!

Nos vemos, un saludo desde Andorra!

Published 3/3/2009 17:28 por Lluis Franco
Comparte este post:

Comentarios

# re: SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (V)

Tuesday, March 10, 2009 6:44 PM por Lluis Franco

Eso espero!

Será el post final de la serie... :-)

Saludos,