Nuxeo/Blogs

Product & Development / All about the Nuxeo Platform, from strategy to feature highlights to dev tricks

[Monday Dev Heaven] Share your content with the outside world

with one comment

Studio Advanced XML Extensions

Studio Advanced XML Extensions

The goal of today’s post is to show you one of the many ways you can expose a document stored in Nuxeo, and share it to the outside world without using Nuxeo’s Document Management user interface. I will take you step-by-step through a small project that makes a document available to an anonymous user, and displays it with a WebEngine Frontend. I’ll be using a Note document as an example, but it could be anything. Let’s use a job offer as our real-life example. Someone puts the offer together and then asks their manager to validate it. Once the manager validates it, the offer is published in a section. After it’s published, we make it available to anyone via an anonymous user, add a permalink, and a special front end for your offer, throw in some “Share on SomeSocialNetwork” buttons, and your content can be shared easily by anyone anywhere. We could add a simple form for them to submit their name, email, and resume. While we are at it, the form could even be used to create a new JobApplication document as a child of the job offer. Maybe I’ll save that last part for the next blog :)

Enable anyone to see a document.

Did you know that you can add custom XP contribution directly in Studio? This is very useful when used with Nuxeo Platform Explorer.

We go to Advanced Settings to create a new XML Extension. I’m going to call it annonymousUserContribution.
Then I paste this code

  <!-- Add an Anonymous user -->
  <extension target="org.nuxeo.ecm.platform.usermanager.UserService"
    point="userManager">
    <userManager>
      <users>
        <anonymousUser id="Guest">
          <property name="firstName">Guest</property>
          <property name="lastName">User</property>
        </anonymousUser>
      </users>
    </userManager>
  </extension>

This adds the anonymous user. Now I can setup permissions in the customary way, through the Manage Rights tab for instance. What I’ll do next is add a ‘Share Document’ button on every published document. Still in Studio, I create a new UserAction called ShareDocument. I want this action to be a visible link on the summary tab, so I choose Document Summary Actions. I’ve chosen ‘Share the document’ as its label. No icon for now. The filter is really simple: I need to select ‘Published document’ in the ‘Current Document is’ property. I’ll also select the Note document type since I only want to share Notes. All that’s left for this action is to create the associated operation.

Share Document Automation Chain

Share Document Automation Chain

So I created a new ShareDocument operation. The goal is to set the Read permissions for the guest user. (If we need the UnShareOperation it is quite simple. The only difference with the shareDocument operation is that I deny Read permissions to the guest user.)

Now that we’ve established the Automation Chain of our ShareDocument operation, everybody can see my document. However, I still need a nice frontend to show the document, and a REST url to share it easily.

The WebEngine Frontend

The simplest way to expose our document is to use Nuxeo IDE to create a new webengine project. I’ll add a new method that can handle urls like http://localhost:8080/nuxeo/site/shared/d7e935cd-e432-4083-bb9e-7e55200dca47/ using the @Path annotation as follows:

@Path("/shared")
@Produces("text/html;charset=UTF-8")
@WebObject(type="MyRoot")
public class MyRoot extends ModuleRoot {

    @GET
    public Object doGet() {
        return Response.status(Status.NOT_FOUND).build();
    }

    @GET
    @Path("{uid}")
    public Object getSharedDocument(@PathParam("uid") String uid) throws ClientException {
    	CoreSession coreSession = ctx.getCoreSession();
    	DocumentRef documentRef = new IdRef(uid);
    	DocumentModel document = coreSession.getDocument(documentRef);
        return getView("index").arg("document", document);
    }

}
WebEngine Front End

WebEngine Front End

This code will render the index template with the document as an argument, which will allow me to access to its metadata. Here is a simple example that shows the title and description of a note, as well as its content. I also added share buttons for twitter, linkedin, and facebook.

My index.ftl file:

<@extends src="base.ftl">
<@block name="header">You signed in as ${Context.principal}</@block>
<@block name="content">
<div style="margin: 10px 10px 10px 10px">
<p><h1>${document.title}</h1></p>
<p>${document.description}</p>
<span>
<a href="https://twitter.com/share" class="twitter-share-button" data-via="ldoguin">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
<div class="fb-like" data-send="true" data-width="450" data-show-faces="true"></div>
<script src="http://platform.linkedin.com/in.js" type="text/javascript"></script>
<script type="IN/Share" data-counter="right"></script>
</span>

<div>${document["note:note"]}</div>

</div>

</@block>
</@extends>

Displaying the FrontEnd link

Now that I have a nice page showing the content of my note, I need to display the page’s link. I will add a custom widget using Nuxeo Studio. First off, I have to write the widget.

My code in share_link_template.xhtml displays the link for published documents only:

<div class="actions_block"
  xmlns:c="http://java.sun.com/jstl/core"
  xmlns:h="http://java.sun.com/jsf/html">

  <c:if test="#{publishActions.isPublishedDocument()}">
   <p><h:outputLink target="_blank" value="#{baseURL}site/shared/#{currentDocument.id}/" >
     #{baseURL}site/shared/#{currentDocument.id}/
   </h:outputLink></p>
  </c:if>

</div>
Permalink to the webengine frontend

Permalink to the webengine frontend

Now that we have the widget, we will need to load it in Studio. Just go to Resources and choose to upload a new Widget. To use the widget, I need to override the Note document type and its header layout. On the header layout I add a title, description and Template widget (check in the Advanced Widgets). When I edit the widget, I’ll be asked to choose a template. I should find the one we previously uploaded in the list.

Now we will see the link to my webengine page each time a note is published, making it that much easier to share :)

Next time I’ll show you how we can extend this project. Maybe by adding some simple comment management, or by creating a document with anonymous user feedback.

On a side note, if you guys have any particular topic that you would like to see addressed, please ask in the comments :)
Thanks for reading!

February 21st, 2012 at 3:47 am

About Laurent Doguin

Laurent works as developer and community liaison at Nuxeo, a software company providing a full Enterprise Content Management Platform, open source, for any kind of content-driven application.