domenica 8 maggio 2011

I favolosi 40 Template

Come riportato da Igor nel suo blog, TechSol ha reso disponibili per SharePoint 2010 alcuni dei 40 Template che erano a disposizione per SharePoint 2007; per l'esattezza 22 template.
Buon divertimento

sabato 30 aprile 2011

Download delle guide di SharePoint 2010in formato CHM

Sono stati da poco messi a disposizione i file CHM dell'SDK di SharePoint 2010; Foundation e Server. Li potete trovare ai seguenti indirizzi.
SharePoint Foundation 2010 CHM
SharePoint Server 2010 CHM

giovedì 28 aprile 2011

Creare Folder con un custom Content Type trimite event receiver

Ho trovato in internet che per creare via codice dei folder in una document library, con un content type custom che eredita da folder si deve usare il codice seguente:

SPWeb currentSite = (SPWeb)properties.Feature.Parent;
SPFolderCollection documentLibrary = currentSite.Lists["My Document Library"].RootFolder.SubFolders;
SPFolder folder = documentLibrary.Add("My Folder Name");
// set the content type id and update it, so that the proper attributes are present
folder.Item["ContentTypeId"] = "0x012000521AACBC415A498390B668D81308E454";
folder.Update();

Ma devo segnalare che questo codice non funziona, per generare un folder con assegnato correttamente il content type bisogna utilizzare un SystemUpdate al posto di un Update.

folder.Item.SystemUpdate();

mercoledì 27 aprile 2011

Recuperare informazioni sull'utente corrente in un form InfoPath 2010

Dopo una lunga pausa, mi ripropongo segnalando un ottimo articolo che spiega come fare ad usare in un form InfoPath 2010 pubblicato sotto SharePoint 2010 le informazioni sull'utente corrente, senza scrivere codice. Il tutto si risolve invocando il web service di SharePoint _vti_bin/UserProfileService.asmx. Quindi creando una Data Connection che si connette a questo Web Service è possibile recuperare le informazioni sull'utente, quali:
UserProfile_GUID
AccountName
FirstName
LastName
PreferredName
WorkPhone
Office
Department
Title
Manager
AboutMe
PersonalSpace
PictureURL
UserName
QuickLinks
WebSite
PublicSiteRedirect
SPS-Dotted-line
SPS-Peers
SPS-Responsibility
SPS-Skills
SPS-PastProjects
SPS-Interests
SPS-School
SPS-SipAddress
SPS-Birthday
SPS-MySiteUpgrade
SPS-DontSuggestList
SPS-ProxyAddresses
SPS-HireDate
SPS-LastColleagueAdded
SPS-OWAUrl
SPS-ResourceAccountName
SPS-MasterAccountName
Assistant
WorkEmail
CellPhone
Fax
HomePhone
Comunque è tutto ben spiegato nell'articolo; anche se si rifà a MOSS 2007 è del tutto valido anche per SharePoint 2010

mercoledì 2 febbraio 2011

PRO: Microsoft Office SharePoint 2010, Administrator

Missione compiuto, dopo la pausa Natalizia sono riuscito a dare l'esame di certificazione 70-668 "PRO: Microsoft Office SharePoint 2010, Administrator".
Il prossimo passo potrebbe essere affrontare gli esami per DEV. Tempo permettendo.

mercoledì 26 gennaio 2011

Duet Enterprise Virtual Launch Summit – February 1st

Il primo di febbraio ci sarà il lancio di Duet Enterprise. Il prodotto di integrazione tra SAP e SharePoint/Office dovrebbe essere finalmente pronto.

Microsoft SharePoint Team Blog
Duet Enterprise for Microsoft SharePoint and SAP
Duet Site

mercoledì 22 dicembre 2010

SharePoint 2010 - Workflow per cambiare i permessi ad un documento

Per un cliente avevo l'esigenza di rendere un documento immodificabile e non cancellabile.
In questo post ho intenzione di raccontarvi come ho risolto il problema con le nuove activity di SharePoint Designer 2010, con una sorpesa finale.
Vi raconterò:
  • Come creare i worflow per togliere e rimettere i permessi al documento
  • Come fare delle custom action accessibili dal ribbon con SharePoint Designer, per eseguire il workflow
  • Come crare delle custom action che tramite ECMA Client Object Model eseguono un workflow associato alla lista
Creare i workflow per manipolari i permissi
Prima di tutto si comincia creando un  nuovo Workflow con SharePoint Designer, molto comodi sono i Globally Reusable Workflow, che possono essere associati a verie liste e usati in tutti i siti della site collection (ricordatevi di premere il pulsante Publish Globally nel ribbon del Designer). Il primo step è quello di creare un Impersonation Step che ci consente di impersonare in fase di esecuzione un altro utente e nella fattispecie l'utente che ha creato il workflow. In questo modo è possibile far eseguire a utenti che non ne avrebbero i permessi determinate azioni.


L'azione da aggiungere è "Replece List Item permissions". Di seguito i passi per aggiungere, modificare o rimuovere permessi ad un item.









Per vedere tutte le immagini.
SP2010 Permission Workflow

Usando l'action "Inherit parent permissions for item..." è possibile riportare la situazione dei permessi alla condizione originale.

Quick Step con SharePoint Designer
Nel ribbon di ogni Library (tab Library), nella sezione "Customize Library" c'è il bottone "New Quick Step". Premendo questo bottone si apre SharePoint Designer sull'edit della lista corrente e viene visualizzato un pannello per configurare una custom action che sarà visibile nel tab Documents sotto la voce "Quick Steps". Da questa interfaccia è possibile associare all'azione: un link ad una pagina aspx del sito, l'avvio di un workflow associato alla lista oppure un link ad una URL esterna. Vedi fugure di seguito.




Custom Action per attivare un workflow
Visto che da Designer è possibile creare una custom action che consente di avviare un workflow, ho voluto provare a creare delle mie custom action,da posizionare in punti diversi del ribbon e con logiche di attivazione tutte mie, che facessero la stessa cosa. Il primo passo è stato cercare di capire quale azione fosse associata e questi Quick Step. Analizzando un po' il codice HTML generato e relativi Javascript ho scoperto, che queste actuion invocano la pagina "/_layouts/wfstart.aspx" con i seguenti parametri:
  • List={ListId}
  • ID={ItemId}
  • TemplateID
  • AssociationName
I primi due parametri sono chiari, l'ultimo è il nome che viene dato al workflow quando lo si associa alla lista, ma TemplateID ho fatto un po' più fatica a capire cosa fosse. Alla fine è risultato essere il GUID dell'associazione del workflow alla lista. Nei miei script è stato semplice ricavare i primi due parametri, l'ultimo ho deciso di metterlo staticamente nel codice (intanto stavo scrivendo action per attivare workflow che associavo io sempre con lo stesso nome), mentre il TemplateID ho sudato un po' a tirarlo fuori usando ECAM Client Object Model (ho spulciato un po' l'SDK). Alla fine il risultato è stato quanto segue:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction
  Id="Install JS"
  ScriptSrc="/_layouts/RibbonButtonsDemo/demo.js"
  Location="ScriptLink"
  Sequence="100">
  </CustomAction>
  <CustomAction Id="SharePoint.Ribbon.LockDocuments"
                Title="Lock Documents"
                Location="CommandUI.Ribbon"
                RegistrationType="List"
                RegistrationId="101">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition Location="Ribbon.Documents.Manage.Controls._children">
          <Button Id="Ribbon.Documents.New.MsysLockDocsButton"
          Alt="Lock selected document"
          Sequence="5"
          LabelText="Lock"
          Image16by16="/_layouts/images/RibbonButtonsDemo/lock-icon16x16.png"
          Image32by32="/_layouts/images/RibbonButtonsDemo/page-lock-icon32x32.png"
          Command="Command.LockButton"/>
        </CommandUIDefinition>
        <CommandUIDefinition Location="Ribbon.Documents.Manage.Controls._children">
          <Button Id="Ribbon.Documents.New.MsysUnlockDocsButton"
          Alt="Unlock selected document"
          Sequence="5"
          LabelText="Unlock"
          Image16by16="/_layouts/images/RibbonButtonsDemo/lock-off-icon16x16.png"
          Image32by32="/_layouts/images/RibbonButtonsDemo/page-lock-off-icon32x32.png"
          Command="Command.UnlockButton"/>
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler Command="Command.LockButton"
                          CommandAction="javascript:ExecuteOrDelayUntilScriptLoaded(LockDocs, 'sp.js');"
                          EnabledScript="javascript:onlyOne();"/>
        <CommandUIHandler Command="Command.UnlockButton"
                          CommandAction="javascript:ExecuteOrDelayUntilScriptLoaded(UnLockDocs, 'sp.js');"
                          EnabledScript="javascript:onlyOne();"/>
      </CommandUIHandlers>
    </CommandUIExtension>
  </CustomAction>
</Elements>
Tutto il codice Javascript lo messo in un file js esterno salvato nella cartella layouts.

var context;
function LockDocs() {
    // First get the context and web
    context = SP.ClientContext.get_current();
    
    this.web = context.get_web(); 
    // Get the current selected list, then load the list using the getById method of Web (SPWeb)
    var listId = SP.ListOperation.Selection.getSelectedList();
    var sdlist = this.web.get_lists().getById(listId);
    this.wfa = sdlist.get_workflowAssociations().getByName('Change permissions');
    context.load(this.wfa);
    context.executeQueryAsync(Function.createDelegate(this, this.OnSuccess), Function.createDelegate(this, this.OnFail));
}

function UnLockDocs() {
    // First get the context and web
    context = SP.ClientContext.get_current();

    this.web = context.get_web();
    // Get the current selected list, then load the list using the getById method of Web (SPWeb)
    var listId = SP.ListOperation.Selection.getSelectedList();
    var sdlist = this.web.get_lists().getById(listId);
    this.wfa = sdlist.get_workflowAssociations().getByName('Re-active Permissions');
    context.load(this.wfa);
    context.executeQueryAsync(Function.createDelegate(this, this.OnSuccess), Function.createDelegate(this, this.OnFail));
}

function OnSuccess(sender, args) {
    var listId = SP.ListOperation.Selection.getSelectedList();
    // Get the currently selected item of the list. This will return a dicustonary with an id field
    var items = SP.ListOperation.Selection.getSelectedItems(context);
    var mijnid = items[0];
    var itemId = mijnid.id;
    var _url = '/_layouts/wfstart.aspx?List=' + listId + '&ID=' + itemId + '&TemplateID=' + this.wfa.get_id() + '&AssociationName=Change permissions';
    alert(_url);
    document.location = _url;
}

function OnFail(sender, args) {
    alert('Fail');
    //alert('Fail to get list list. Error :'+ args.get_message());
}

function moreThanOneEnabled() {
    var items = SP.ListOperation.Selection.getSelectedItems();
    var ci = CountDictionary(items);
    return (ci > 0);
}

function onlyOne() {
    var items = SP.ListOperation.Selection.getSelectedItems();
    var ci = CountDictionary(items);
    return (ci == 1);
}

Come potete vedere recupero il TemplateID dal workflow associato, nel metodo di feedback OnSuccess.

Sorpresa
La sorpresa consiste nel fatto che in SharePoint 2010 esiste una nuova funzionalità (una feature da attivare a livello di site collection), chiamata "In place Record", che fa proprio quello che serviva al mio cliente e in modo più elegante. Quindi tutta la fatica fatta è servita solo a titolo di studio :-)

martedì 9 novembre 2010

TS: Microsoft Office SharePoint 2010, Configuring

Passato con successo anche l'esame 70-667 "Microsoft Office SharePoint 2010, Configuring".
Adesso proverò ad affrontare il 70-668.

domenica 3 ottobre 2010

Inviare una mail a SharePoint

Credo che la maggior parte degli utilizzatori sappia che è possibile inviare una mail ad una lista di SharePoint, dopo aver configurato l'incoming mail nella console di ammministrazione. Ma forse non tutti sanno che solo alcune liste sono preproste a ricevere mail. Per esempio la custom list non può ricevere mail OOTB, ovvero non ha un handler associato OOTB.
Le liste che possono ricevere mail sono:
  • Announcements
  • Events (Calendar)
  • DocumentLibrary
  • PictureLibrary
  • XMLForm
  • DiscussionBoard
  • Blog
Questo in SharePoint 2007 di certo e sono sicuro che poco sia cambiato in SharePoint 2010 sotto questo punto di vista. Non ho provato tutte le liste, ma di certo la più interessante è l'Announcements che consente di vedere la mail completa nel campo Body, il Subject nel campo Title e gli allegati della mail, come allegati dell'item.
Per completare il discorso vi elenco gli Handler preprosti per ogni lista:
  • Announcements - SPAmmouncementsEmailHandler
  • Events - SPCalendarEmailHandler
  • DocumentLibrary, PictureLibrary e XMLForm - SPDocLibEmailHandler
  • DiscussionBoard - SPDiscussionEmailHandler
  • Blog - SPBlogPostEmailHandler
Alle liste che non derivano da un BaseTemplate  viene associato un SPExternalEmailHandler.
E' possibile infine associare ad una custom list un event receiver per gestire la ricezione di una mail implementando il metodo EmailReceived della classe SPEmailEventReceiver.