In the recent request for community members to name their favourite workflow action, I put forward the "Copy To SharePoint" action, this was down simply to the element of surprise, that it helped me do exactly what I wanted to, easily, with no hacking, or fudging, as we call it.
I had a requirement for attachments in an event calendar to be treated like true SharePoint managed documents when uploaded by users.
We've created an OOTB calendar. We've also created a document library called "Event Resources" and in that library we've added some Site columns, the ones that will contain metadata in the event calendar that we want to associate with the document. The meatdata is important because we will use it later to give the users a nice way of viewing the documents.
We will create a workflow that will run on Create or Modfied and the first action we will insert is "Copy to SharePoint", this action will basically try to copy the event item to a document library, but it's actually going to copy the attachment into the document library as a document in it's own right, and by ensuring we tick "Copy item meta data" it will add the metadata to the document in the library as well. Perfect.
Shout out to Paul Crawford who helped me see the errors of my ways with the convaluted approach I was taking to this next part. So we need to now delete these attachments, after all, they are no longer needed here and we don't want to duplicate the data. So we're going to Call a WebService.
We're going to be using the lists.asmx WebService and we'll invoke the "GetAttachmentColleciton" method. Pass it our list (the calendar) name and the ID of the current item and store it in a Multiple lines of text field as it will be spat out in XML.
We're going to be querying the XML we just got and storing the URL's in a collection. The XML node is simply called "Attachment" so configure your action as below.
Use the "For Each" action to iterate your way through the collection storing the attachment url from the collection into a text variable. We're going to use another "Call WebService" action and use the lists.asmx WebService again to delete the attachment. The for each will loop through, so for multiple attachments they will all be deleted.
So you can see we're just passing the calendar name, the ID and the url given to the attachment. It's important to do it this way because the WebService encodes the URL differently, using "+" for spaces rather than %20, so getting the URL through a WebService ensures that it's correctly formatted.
Finally, we're going to have to present this to the user in a nice friendly way when they open up the event item, so we want to edit the list form and add the list view webpart for our "Event Resources" library to the bottom of the form and create a connection from the event item webpart to the list view webpart on a common piece of metadata. In this case I used Title, but it might be whatever suits you to ensure it's unique.
So there we go, 2 working documents linked nicely to our event.