Convertir un document Office docx en page html grâce à SharePoint–Partie 3

Posted on Updated on

Rappels

Dans les deux parties précédentes : Partie 1 et Partie 2, nous avons vu comment activer le service de conversion de documents à l’aide de l’administration centrale de MOSS 2007 puis comment créer les types de contenus et les bibliothèques de documents. Bien sûr, nous avons créé un package de déploiement avec WSPBuilder afin d’appliquer ces personnalisations sous la forme de fonctionnalités (features) dans SharePoint.

Une fois ce travail réalisé, dans cette partie donc, nous allons créer une action personnalisée (Custom Action) permettant de rediriger l’utilisateur vers une page personnalisée qui lancera la conversion.

Puis nous verrons comment démarrer un Workflow sur la finalisation de l’activité de conversion de documents.

C’est parti !

Création de la Custom Action

Qu’est-ce qu’une Custom Action ou Action Personnalisée ?

Une action personnalisée permet d’insérer des boutons, des liens dans les menus standards de SharePoint. Il sera donc possible au développeur d’ajouter des entrées dans le menu “Actions du site”, le menu de login, le menu contextuel sur chaque élément de liste, etc.

Elles permettent de s’intégrer facilement à l’interface de SharePoint afin d’y greffer ses propres éléments de menus. Ces custom actions ou actions personnalisées doivent être ajoutées dans une fonctionnalité (Feature) afin d’être déployées dans SharePoint.

Revenons à la solution Visual Studio précédemment créée. Nous allons maintenant ajouter cette custom action afin qu’elle soit déployée avec les types de contenus, les définitions de liste, etc. Nous allons également associer cette Custom Action avec la définition de liste pour que la nouvelle entrée dans le menu contextuel n’apparaisse que dans le contexte de cette liste (sur une instance d’une liste créée à partir de cette définition).

Cette action personnalisée se développe sous la forme d’une structure XML que l’on ajoutera à la définition de la feature.

Souvenez vous, dans la définition de la feature, nous avions précédemment déclaré un fichier “Elements.xml” dans le fichier “feature.xml” :

61

Ouvrons donc ce fichier “elements.xml” et ajouter la déclaration XML :

62

Dans cette déclaration :

  • Id = Un identifiant unique pour la custom action, format string ou GUID
  • Title = Texte qui sera affiché dans le menu de SharePoint
  • Location = localisation du menu dans l’interface SharePoint (voir tableau ci-après)
  • Description = Description longue de l’entrée de menu
  • RegistrationId = Identifiant du modèle visé (ici notre définition de liste, Type=1001)
  • RegistrationType = Type d’objet visé par l’action, ici “List”
  • Sequence = Ordre de l’entrée dans le menu : 0 en haut, supérieur à 0 vers le bas
  • Un sous élément UrlAction (voir après le tableau).

Vous pourrez trouver ici les autres paramètres disponibles pour la déclaration de l’action personnalisée à cette adresse : http://msdn.microsoft.com/fr-fr/library/ms460194(v=office.12).aspx.

Revenons à l’attribut “Location”. Ce paramètre indique à SharePoint où ajouter l’élément de menu. Vous trouverez ici : http://msdn.microsoft.com/fr-fr/library/bb802730(v=office.12).aspx toutes les possibilités afin de placer votre custom action.

Reste le dernier élément : “UrlAction”. Cela représente tout simplement l’adresse vers laquelle sera redirigé l’utilisateur lors du clic sur notre entrée de menu.

Ici donc, on utilise certaines variables : les “Jetons d’Url” disponibles lors de la déclaration d’une custom action comme ~site == site web courant, ~sitecollection == collection de sites et qui permettent de recomposer l’Url pour la redirection, sans faire de code qui devrait recomposer l’adresse.

D’autres “Jetons d’Url” sont également disponibles comme {ItemId} == identifiant de l’élément, {ListId} == identifiant de la liste, etc.

Vous pourrez trouver d’autres renseignements ici : http://msdn.microsoft.com/fr-fr/library/ms473643(v=office.12).aspx.

Dans l’exemple, on redirige l’utilisateur vers une page stockée dans le répertoire layouts > Exemple > PagesAdmin et qui s’appellera “ConvertDoc.aspx” avec ces paramètres :

  • ID = {ItemId} : identifiant de l’item courant
  • ListId = {ListId} : identifiant de la liste courante
  • SourceUrl = {ItemUrl} : Url de l’item courant => url de redirection lors de l’annulation
  • SiteUrl = {SiteUrl} => url pour la redirection

Attention certains nom de paramètres sont très mal acceptés par SharePoint, j’en avais déjà parlé dans un article précédent : https://kazoumoulox.wordpress.com/2009/04/07/sharepoint-aucun-element-nexiste-a-lemplacement/.

Pensez à séparer les paramètres dans l’url avec des “&” qui équivaut à ‘&’ en html encodé.

Page de conversion

Il nous reste maintenant à créer la page qui sera appelée lors du clic… Nous savons déjà où la déployer et donc la placer dans la solution WSP !

En effet, dans l’UrlAction, nous avons spécifié une adresse qui renvoie vers une page stockée dans le répertoire 12/TEMPLATE/LAYOUTS. Pour ajouter la page, ajouter dans la solution Visual Studio le dossier LAYOUTS, puis le sous répertoire Exemple et enfin un sous répertoire PagesAdmin comme suit :

63

Nous allons maintenant ajouter la page ASPX ConvertDoc et son fichier de code behind. Pour cela, dans le répertoire PagesAdmin ajouter un fichier ConvertDoc.aspx.

Puis ajouter un répertoire Code et dedans un fichier ConvertDoc.cs (Ce fichier sera compilé dans l’assembly mais pas déployé tel quel sur le disque du serveur, on le met donc en dehors du répertoire 12) :

64

La structure est prête, maintenant place au CODE !!!

Première chose, renseigner le fichier aspx afin de lui indiquer que le code exécuté sera cela de la classe ConvertDoc contenue dans ConvertDoc.cs

On ouvre ConvertDoc.cs et on renseigne :

  • Le namespace : namespace Exemple.Pages.BackOffice
  • L’héritage de la classe : public class ConvertDoc : LayoutsPageBase (obligatoire pour une page placée dans le répertoire Layouts)
  • Les using utiles : au moins Microsoft.SharePoint en plus et pensez à ajouter les références vers les assemblies que vous allez utiliser comme System.Web.

65

Puis on va dans le fichier aspx et on ajoute les directive indiquant dans quelle classe se trouve le code behind de cette page, ainsi que l’import des DLL de SharePoint :

image

  • Première ligne : Assembly = On indique dans quelle assembly sera situé le code behind (nom complet : Name, Version, Culture et PublicKeyToken).
  • Seconde ligne : Langage de compilation (C#), et classe de laquelle devra hériter cette page : Exemple.Pages.BackOffice.ConvertDoc, masterpage utilisée : ~/layouts/application.master.
  • Troisième ligne : Import de l’assembly Microsoft.SharePoint
  • Quatrième ligne : Déclaration du TagPrefix SharePoint pour utiliser les composants/contrôles contenus dans la DLL Microsoft.SharePoint, dans le namespace : Microsoft.SharePoint.WebControls.

Il faut également déclarer certain contrôles Content utilisés par SharePoint (dans la masterpage avec les ContentPlaceHolderIDs) comme ceux utilisés pour le titre de la page, titre de la fenêtre Internet Explorer, la zone centrale, etc.

Pour cela, on utilise une déclaration de la forme :

<asp:Content ID=”Content1″ ContentPlaceHolderID=”PlaceHolderPageTitle” runat=”server”>
<SharePoint:EncodedLiteral ID=”EncodedLiteral1″ runat=”server”  Text=”Conversion de documents Word en Html”  EncodeMethod=’HtmlEncode’ />
</asp:Content>

Nous pouvons déjà vérifier que la custom action et la page sont correctement déployés et qu’ils sont bien intégrés à SharePoint. Pour cela, on compile la solution puis on la déploie à l’aide de WSPBuilder (voir partie 2).

En créant une nouvelle bibliothèque de document basée sur le modèle créé dans la partie 2, on ajoute un nouveau document. Une fois créé, on fait apparaitre le menu contextuel de l’élément et on vérifie que notre nouvelle entrée de menu soit bien présente :

image

Et en cliquant sur le lien, on arrive sur la page ConvertDoc (Dans laquelle j’ai déjà placé quelques contrôles comme une liste déroulante (DropDownList) et des LiteralControls) :

image

Nous allons donc remplir cette page, la structurer avec des contrôles asp.Net et coder les actions réalisées par ces contrôles.

Mais à quoi vont servir les contrôles dans cette page ? Tout simplement à choisir la bibliothèque de Pages d’un site de publication, que ce soit le site courant (racine) ou un sous site. Ainsi, on pourra depuis le site racine, créer des pages dans ce même site mais aussi dans ses sous sites de type publication.

On aura donc une bibliothèque de documents d’entrée et une fonction de conversion//routage de la page convertie vers une bibliothèque de pages.

Première chose, ajouter les contrôles dans la page en reprenant le style général des pages de backoffice de SharePoint. Pour faire cela, j’ai juste ouvert une page dans Internet Explorer et affiché la source… puis réutilisé le html que j’ai récupéré.

Pour pouvoir indiquer un titre à la page (fenêtre IE), un titre général et une description, j’ai ouvert cette même page dans Notepad, pour récupéré les ID des ContentPlaceHolders adéquats. Ce qui donne :

  • PlaceHolderPageTitle : Titre de la fenêtre Internet Explorer
  • PlaceHolderPageTitleInTitleArea : Titre dans la zone de titre de la page web
  • PlaceHolderPageImage : Image placée dans la zone de titre (vide dans l’exemple suivant)
  • PlaceHolderPageDescription : Description de la page courante

Dans la page :

<asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
<SharePoint:EncodedLiteral ID="EncodedLiteral1" runat="server" Text="Conversion de documents Word en Html" EncodeMethod='HtmlEncode' />
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
    <asp:Literal ID="lblDescription" runat="server" Text="Conversion de documents Word en Html" />
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="PlaceHolderPageImage" runat="server">
    <img src="/_layouts/images/blank.gif" width="1" height="1" alt="">
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="PlaceHolderPageDescription" runat="server">
    <SharePoint:EncodedLiteral ID="EncodedLiteral2" runat="server" Text="Conversion de documents Word en Html" EncodeMethod='HtmlEncode' />
</asp:Content>

Puis viendrons les contrôle de la page dans le ContentPlaceHolder Main :

<asp:Content ID="ContentMain" ContentPlaceHolderID="PlaceHolderMain" 
        runat="server">
	...
	...
</asp:Content>

Dans le fichier C#, on va déclarer les contrôle utilisés côté serveur, comme la liste déroulante qui sera remplie en utilisant le modèle objet SharePoint.

On trouve en premier quelques paramètres utiles :

private static string ItemIDParamName = "ID";
private static string ListIdParamName = "ListId";
private static string SourceUrlParamName = "SourceUrl";
private static string SiteUrlParamName = "SiteUrl";
private static string TranformerGuid = "6dfdc5b4-2a28-4a06-b0c6-ad3901e3a807";
private static Guid workflowGuid = new Guid("f3a6ce63-5696-4e0d-af6d-077c69b4f424");
  • Les noms des paramètres utilisés dans la QueryString (ID, ListId, SourceUrl et SiteUrl).
  • Le Guid représentant le “transformateur” => type de conversion utilisé par le job de conversion de documents.
  • Un Guid pour le workflow qui sera déclenché à la fin de la conversion.

Je n’ai pas encore bien expliqué le fonctionnement de cette page. En effet, lors du clic sur la custom action, SharePoint redirige l’utilisateur sur cette page. On affiche la liste déroulante proposant les bibliothèques de pages disponibles. Une fois cette dernière choisie, l’utilisateur clique sur “OK”, la conversion se lance (page d’attente de conversion).

La conversion terminée, on redirige vers cette même page, mais cette fois on propose à l’utilisateur de déclencher un workflow on de retourner à la page de départ (affichage de l’élément). Pour indiquer qu’on est dans la seconde étape, on utilisera des paramètres supplémentaires dans l’url :

  • converted : indique si le document est converti => true
  • targeturl : indique l’url du fichier converti

Premier étape : choix de la bibliothèque de sortie

1/ On teste le mode

2/ On initialise les contrôles de la page

3/ On charge les sites et webs et on parcours à la recherche des bibliothèques de type Pages

if (string.IsNullOrEmpty(GetFromQueryString("converted")) || 
     string.IsNullOrEmpty(GetFromQueryString("targetUrl")))
{
    InitializeControls();

    //La liste est chargée vite & inactive 
    using (SPSite currentSite = new SPSite(SPContext.Current.Site.ID)
    {
        using(SPWeb currentWeb = currentSite.OpenWeb(SPContext.Current.Web.ID))
        {
            PublishingWeb pubWeb = PublishingWeb.GetPublishingWeb(currentWeb);
            if(pubWeb != null)
            {
                 GetPagesListInPubWebs(pubWeb);
            }
        }
     }
     if (listToPublish != null && listToPublish.Count > 0)
     {
         LibraryList.Enabled = true;
         LibraryList.Items[0].Selected = true;
         selectedValueFromDDL = LibraryList.Items[0].Value;
         BtnOk.Enabled = true;
     }
}

Et la méthode de récupération récursive des bibliothèques de pages :

private void GetPagesListInPubWebs(PublishingWeb pubWeb)
{
     SPList pages = pubWeb.PagesList;
     if (pages != null)
         listToPublish.Add(pages);

     PublishingWebCollection pubs = pubWeb.GetPublishingWebs();
     if (pubs != null)
     {
         foreach (PublishingWeb pub in pubs)
         {
            GetPagesListInPubWebs(pub);
         }
     }

}

66

Lancement de la conversion de documents :

//Lancer la conversion en html
PublishingWeb targetPubWeb = PublishingWeb.GetPublishingWeb(targetWeb);
if (targetPubWeb != null)
{
    PublishingPageCollection Pages = targetPubWeb.GetPublishingPages();
    if (Pages != null)
    {
        using (SPLongOperation lo = new SPLongOperation(this))
        {
             lo.LeadingHTML = "Conversion du document en cours...";
             lo.TrailingHTML = "La conversion du document Word en Html est en cours.";

             lo.Begin();

             PublishingPage newPage = Pages.Add(currentFile.Item.DisplayName + ".aspx", currentFile, new Guid(TranformerGuid), PageConversionPriority.High);
             //newPage.CheckIn("Nouvelle page publiée");
             newPage.ListItem[SPBuiltInFieldId.Title] = currentFile.Item[SPBuiltInFieldId.Title];

             newPage.Update();

             currentFile.Item["Lien"] = string.Format("{0}{1}", targetPubWeb.Url.EndsWith("/") ? targetPubWeb.Url : targetPubWeb.Url + "/", newPage.Url);
             currentFile.Item.SystemUpdate(false);

             //lo.End(string.Format("{0}{1}", targetPubWeb.Url.EndsWith("/") ? targetPubWeb.Url : targetPubWeb.Url + "/", newPage.Url));
             lo.End(string.Concat(SiteUrl.EndsWith("/") ? SiteUrl : SiteUrl + "/", "_layouts/Exemple/PagesAdmin/ConvertDoc.aspx?ID=", ItemID,
                           "&ListId=", ListId, "&SourceUrl=", SourceUrl, "&SiteUrl=", SiteUrl,
                           "&converted=1&targetUrl=", string.Format("{0}{1}", targetPubWeb.Url.EndsWith("/") ? targetPubWeb.Url : targetPubWeb.Url + "/", newPage.Url)));

          }
      }
      else
           throw new Exception("La bibliothèque de pages cible n'a pas pu être trouvé.");
}

Ici on utilise une méthode de la classe PublishingPagesCollection, la méthode Add() qui permet de passer en paramètre le transformer GUID permettant d’indiquer qu’il faut effectuer une conversion de documents avant d’ajouter le fichier dans la bibliothèque de pages du site choisi.

A noter également que l’on utilise l’API SPLongOperation qui permet d’encapsuler l’exécution d’une procédure afin d’afficher dans SharePoint la page d’attente standard.

67

Deuxième étape : lancement du workflow

Lorsque la conversion est terminée, on redirige (Postback) l’utilisateur sur la même page, en ajoutant des paramètres dans l’url indique que la conversion est terminée et l’url de sortie du fichier converti. On peut donc afficher dans la page une CheckBox demandant si l’utilisateur souhaite déclencher l’association d’un workflow avec cette nouvelle page (par exemple un workflow d’approbation).

Si cette CheckBox est cochée et que l’utilisateur clique sur le bouton “OK”, alors on effectue cette association.

Notez qu’on indique aussi l’url vers le fichier converti afin de vérifier le résultat de cette conversion :

68

1/ Récupération des paramètres depuis la QueryString

2/ Récupération de l’item où “attacher” le workflow

3/ Associer le workflow et l’item, et le démarrer.

//Si l'utilisateur a choisi de lancer l'approbation, démarrage du workflow
if (ckbAppro.Checked)
{
    //récupération des paramètres
    string ItemID = GetFromQueryString(ItemIDParamName);
    string ListId = GetFromQueryString(ListIdParamName);
    string SourceUrl = GetFromQueryString(SourceUrlParamName);
    string SiteUrl = GetFromQueryString(SiteUrlParamName);
    string valueTargetSite = LibraryList.SelectedItem.Value;

    if (!string.IsNullOrEmpty(ItemID) && !string.IsNullOrEmpty(ListId) && !string.IsNullOrEmpty(SourceUrl) && !string.IsNullOrEmpty(SiteUrl) && !string.IsNullOrEmpty(valueTargetSite))
    {
        SPListItem currentItem = GetItemFormListAndId(ListId, ItemID, SourceUrl);
        if (currentItem != null)
        {
            SPWorkflowAssociation wrkAsso = currentItem.ParentList.WorkflowAssociations.GetAssociationByBaseID(workflowGuid);
            if (wrkAsso != null)
            {
                currentItem.Web.Site.WorkflowManager.StartWorkflow(currentItem, wrkAsso, wrkAsso.AssociationData, true);
                SPUtility.Redirect(currentItem.ParentList.DefaultViewUrl, SPRedirectFlags.Default, HttpContext.Current);
            }
        }
    }
}

Voila, la série d’articles se termine… voici les sources utilisées tout le long : Exemple Conversion

Bon code !

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s