Twitter Dashlets 2.5 Released

If you’ve tried Share Extras‘s Twitter add-ons recently then you might know that the Twitter Dashlets add-on for Alfresco 4 bundles up two similarly-named add-ons that I released last year.
Using the dashlets that the add-on provides, you can follow a particular user or Twitter list, or follow the results of a Twitter search, direct from your Share Dashboard. Great for monitoring the results of a social media campaign related to a particular site, or just topics that are important to you.
But the dashlet that I’m now using the most is the Twitter Timeline dashlet that allows you to easily connect to Twitter’s authenticated resources via OAuth, which I showed at last year’s Alfresco DevCon.
Release 2.5 tidies up a number of bugs but more importantly now provides a consistent experience across all three dashlets, in a couple of areas.
You can view a short video of the updated dashlets or submit feedback on the Share Extras site.
Authenticated access
The Reply, Retweet and Favorite actions were always present on the Twitter Timeline dashlet but now also appear on the other dashlets too, if you have previously connected your Share user account to a Twitter profile.
Twitter dashlet actions
This has the added benefit that you will be able to view the protected tweets of any users you follow in the Twitter Feed dashlet, since requests will always be authenticated whenever you are connected.
Notifications
All three dashlets will periodically poll for new Tweets, and the notifications have been made more compact and added into the dashlet title bar
Twitter Timeline notifications
To load the new tweets, just click the green notification icon.
More options for Search results
The Twitter Search dashlet now allows you to choose between recent tweets, ‘top’ tweets as rated by Twitter, or a mix of the two.

Refreshing Web Scripts from Ant

I’ve always been a big fan of using Ant to automate some of the more mundane tasks such as building packages, when developing Share add-ons like the 20 now available on Share Extras, and the Sample Dashlet project now hosted on there now provides a template for others to use in their own projects.
That project’s build script provides a target to hot-copy files into a running Tomcat instance for local testing, but whenever I’ve updated web script components (either on the repo side or in Share) I’ve had to remember to hit the Refresh Web Scripts button on the scripts index page. This calls the Web Scripts Maintenance page, which is actually a web script itself.
Since I was doing a small bit of work this week to provide a couple of new custom document actions, I figured it was worth looking again for a more automated solution to this.
Ant comes complete with it’s own Get Task which can make outgoing HTTP calls, but as the name implies it’s limited to GETs only and not the POSTs required to hit the Web Scripts Maintenance page. So I started looking for alternatives.
Ant’s Sandbox does provide a HTTP module which can apparently make other requests, but the lack of any updates since 2007 did not bode well, and the lack of any documentation was too much of a barrier anyway. Lastly I revisited the Ant-Contrib tasks which I’d experimented with a while back, but again there were no recent updates and the library still did not support the authentication necessary to call the Maintenance web script.
Finally via a thread on Stack Overflow, I came across this project by Alex Sherwin, which is actively being maintained and supports POST requests with authentication and request parameters. Exactly what I needed.
So I added the following definitions to my build script, which seem to work well on 3.4.
<!-- Tomcat properties to reload web scripts or the manager webapp -->
<property name="tomcat.url" value="http://localhost:8080" />
<property name="tomcat.repo.url" value="${tomcat.url}" />
<property name="tomcat.share.url" value="${tomcat.url}" />
<!-- Tomcat properties to reload web scripts -->
<property name="webapp.alfresco.path" value="/alfresco" />
<property name="webapp.share.path" value="/share" />
<property name="post.verbose" value="false" />
<property name="repo.admin.username" value="admin" />
<property name="repo.admin.password" value="admin" />
<property name="repo.scripts.index" value="${tomcat.repo.url}${webapp.alfresco.path}/service/index" />
<property name="share.scripts.index" value="${tomcat.share.url}${webapp.share.path}/page/index" />

<path id="ml-ant-http.classpath">
    <fileset dir="lib">
        <include name="ml-ant-http-1.1.1.jar" />
    </fileset>
</path>

<taskdef name="http" classname="org.missinglink.ant.task.http.HttpClientTask">
    <classpath>
        <path refid="ml-ant-http.classpath" />
    </classpath>
</taskdef>

<!--
Web script reloading from Ant. These tasks use the HTTP task from
http://code.google.com/p/missing-link/.
-->
<target name="reload-webscripts-repo" depends="" description="Reload repository webscripts">
    <http url="${repo.scripts.index}"
        method="POST"
        printrequest="false"
        printrequestheaders="false"
        printresponse="false"
        printresponseheaders="false"
        expected="200"
        failonunexpected="true">
        <credentials username="${repo.admin.username}" password="${repo.admin.password}" />
        <query>
            <parameter name="reset" value="on" />
        </query>
    </http>
</target>

<target name="reload-webscripts-share" depends="" description="Reload Share webscripts">
    <http url="${share.scripts.index}"
        method="POST"
        printrequest="false"
        printrequestheaders="false"
        printresponse="false"
        printresponseheaders="false"
        expected="200"
        failonunexpected="true">
        <credentials username="${repo.admin.username}" password="${repo.admin.password}" />
        <query>
            <parameter name="reset" value="on" />
        </query>
    </http>
</target>

I’ve tried to structure the properties to cater for most peoples’ development settings, for example if you have separate Tomcats running the repo and Share on different ports, then you can specify different values for -Dtomcat.repo.url and -Dtomcat.share.url when you call the script. You should see that the username and password used to authenticate to the web script can be easily overridden if you have changed the default values.
The scripts haven’t yet been tested against v3.3, but I suspect that the share.scripts.index property will need overriding in this version in order to use the ‘service’ servlet name instead of ‘page’ used in 3.4, e.g. -Dshare.scripts.index=http://localhost:8080/share/service/index .
There’s just a couple of negatives. I couldn’t figure out how to make the http task a little less verbose with it’s output, but I’m sure that will be addressed in time. Also it would be good if the Maintenance web script came with a plain text output template rather than just HTML, as although it would be useful to output the result from the script (which shows the number of web scripts currently/previously loaded, plus any problems), the HTML markup isn’t really readable enough to echo to the terminal.
Since the changes seem pretty stable, I’ve added these to the Sample Project in Subversion. You can try it out yourself by grabbing a copy of the build.xml file as well as the JAR file ml-ant-http-1.1.1.jar from the lib directory. I’ll put a new release of the project ZIP file out in the coming days.
Lastly, here’s a screenshot of the Execute Script action that I was able to test using the new build script.
Execute Script action

New Additions to Share Extras

In the run-up to Alfresco’s Kick Off event in Orlando at the end of March, I spent a bit of time adding some new items into Share Extras and tweaking some of the existing add-ons. Now with the presentation done and the slides up on SlideShare, I thought it would be useful to post a summary of some of the new additions, which bring the total number of add-ons to 19.
Site Geotagged Content Dashlet
The Site Geotagged Content dashlet embeds a map display in the dashboard, with geotagged content marked on the map. Currently Google Maps is used to render the map, based on the method used by the map dashlet distributed with the Calais Integration forge project.

When I originally blogged about the 0.1 version of the dashlet, the map zoom was fixed in the code and the centre was auto-calculated as the mean of all the content item coordinates. Version 0.2 changed this, defaulting to a zoom level of 1 (the whole world) and allowing the user to change the zoom and centre using the map controls, but ensuring that the settings are saved in your user preferences.
So now you can change the view as needed, navigate to another page and then come back to the same map view on your dashboard. The bounds of the map are also now sent with the query to get the list of geotagged items, so even on sites with large numbers of geotagged items only items which will be visible on the map are returned.
Train Times Dashlet
The new Train Times dashlet displays train status information from the National Rail Enquires web site. It’s designed to provide another example of a dashlet loading third-party data (similar to the existing BBC Weather dashlet), but also to demonstrate the use of a few of the more advanced YUI widgets such as DataTables and AutoComplete controls.

Data is loaded from the National Rail Enquiries web site as JSON, but the dashlet uses a second web-tier web script to act as a proxy, loading the data and performing some minor reformatting to better work with the YUI DataSource used by the client-side code.
As well as departure times the web service also provides details of any service disruptions reported at the selected station(s), which are displayed at the top of the dashlet.
Flickr Slideshow Dashlets
The Flickr Slideshow dashlets will display a slideshow display of photostreams sourced from Flickr’s public API. The dashlets are able to display public photos from three types of feed.

  • User photos
  • User contacts photos
  • User favourite photos


The dashlets show how rich effects such as those provided by YUI’s Animation module can be used to display images on the dashboard.
iCalendar Feed Dashlet
The new iCalendar Feed dashlet complements the RSS dashlet provided with Share, displaying upcoming events from any public iCalendar feed. The dashlet has been well-tested with the Alfresco Events feed, but it should also work with other public feeds such as those exposed by Google Calendar.

Wiki Rich Content Customisations
Hopefully a slight change from all these custom dashlets! The Wiki Rich Content add-on provides a number of customisations to the Alfresco Share wiki component to improve it’s visual appearance, and add support for dynamic tables of contents and syntax-highlighted code using Google Code Prettify.

Node Browser Administration Console Component
This is the first example on Share Extras of an additional Admin Console component. The Node Browser component defines a Share administration console component to navigate and view information on nodes stored in the repository stores, similar to its namesake in Alfresco Explorer.

Document Geographic Details Component
Like the Site Geotagged Content dashlet, the Document Geographic Details component displays a map view, this one being designed to integrate into the Document Details page in Share’s Document Library to show the location of that item on the map, when Latitude and Longitude values are available.

Define Your Own Projects

All of the add-ons I’ve mentioned in this post, along with a range of others, are available from the Share Extras project site. The aim of the project is to demonstrate how different types of Share extensions can be developed using scripting and templating, following best practices.
All of the dashlets and other add-ons can be downloaded from the site in JAR format and easily installed into an existing Share installation, so please grab a copy of any that you find interesting and let us know how you get on. For any problems that you find, please use the Issues section on the site.
But really the ultimate aim of the project is to inspire other contributors to come up with their own ideas for dashlets. To make this as easy as possible I’ve created a Sample Dashlet project, which bundles a few files from a basic Hello World dashlet in a basic structure that you can re-purpose to define your own dashlets. Kudos to Erik for the idea.
For now I’ll be focusing myself as I get time on tidying up a few known issues with the existing 19 add-ons. But if you have a great idea for a dashlet or other add-on, please file an issue, use the sample project to get going with the implementation yourself, and consider contributing it to the project if you think others could benefit from it.

Erik Winlöf

Visualising Geotagged Content with Google Maps

Following Steve Reiner’s Twitter post last week, I was inspired over the weekend to add a similar Google Maps-based dashlet to share-extras, to show the locations of geotagged content items on a map view.
Since the repository has full support for extracting geographic data using Tika in version 3.4, all I needed to do to assemble some test content was upload a few photos taken on my phone into the site Document Library.
If you look at the Document Details page of a geotagged photo, you’ll see that this displays a latitude and longitude value at the end of the item’s properties list. These are part of a new aspect named Geographic.

Latitude and Longitude on the Document Details page

Latitude and Longitude


Using Firebug’s Net console, I noticed that the JSON data for the document list view makes these values available on a new geographic property placed on each list item.
Firebug Net Console

Firebug's Net Console


So to keep things simple the initial version of the dashlet simply re-used the doclist web script to grab a list of all content items in the root of the document library space, but the final version now on share-extras comes bundled with a dedicated webscript to list all items in the site that have the Geographic aspect applied.
Using this data, the dashlet displays a marker for each geotagged item, auto-centering itself on the centre point of all the items.

Clicking on a marker takes you to the Document Details page for that item. In the next update I’ll look at displaying a snippet of information for the item, which the Google Maps API makes pretty easy.

From Web Scripts to Portlets with Alfresco 3.4

Since Alfresco 3.2r the ProxyPortlet support in Alfresco Share has allowed developers to easily embed specific bits of Share functionality into a portal such as Liferay, using only a small amount of XML configuration to wire in existing web scripts.
This support has been substantially improved in version 3.4 of Alfresco, in order to allow the entire Share Document Library page to be embedded within a portal. Unfortunately the changes mean that the steps in Luis’s original tutorial no longer work in the latest version.
As one of the features we demonstrated today at our Madrid event was the Doclib portlet, I managed to get five minutes to get the original web script-backed method working too.
Since the CMIS repository browsing web scripts used in Luis’s example are no longer shipped with Share, I used my own Hello World dashlet from share-extras as a starting point instead. The web script is basic, but demonstrates displaying a simple greeting to the user including their user name.
Hello World Portlet
The following steps should work using a recent version of Alfresco 3.4 and Liferay 5.2.3 running as the portal, provided that the two components are first set up as per the Installing and Configuring instructions for the Doclib Portlet.
Once you’ve set everything up, the first thing to do is to add the web script files to the instance of Share that you have already deployed to Liferay. Since you should already have created some directories in Liferay’s tomcat-x.x.x/shared/classes directory to define your share-config-custom.xml, the easiest thing is to create a new directory named site-webscripts within the existing tomcat-x.x.x/shared/classes/alfresco/web-extension and place the following files in it.
org/alfresco/test/hello-world.get.desc.xml

<webscript>
   <shortname>Hello World</shortname>
   <description>Displays Hello World text to the user</description>
   <authentication>none</authentication>
   <url>/test/hello-world</url>
</webscript>

org/alfresco/test/hello-world.get.html.ftl

<html>
   <head>
      <title>${msg("header")}</title>
   </head>
   <body>
      ${msg("label.hello", user.id)}
   </body>
</html>

org/alfresco/test/hello-world.get.properties

header=Hello World!
label.hello=Hello {0}

With those files added, you’ve successfully defined the web script that we’ll wire into Share in the next section.
Now although the web script itself will be automatically picked up by Share at load-time, some additional config is also needed in web.xml for the ProxyPortlet to work in version 3.4.
The following lines, which define a custom servlet and servlet mapping which will be invoked by the ProxyPortlet, should be placed in the web.xml file belonging to the Share instance which has been deployed in Liferay. You should find the path to this will be something like <LIFERAY_HOME>/tomcat-6.0.18/webapps/share/WEB-INF web.xml (if you have not already started Liferay you will need to do so to force it to deploy share.war and create this structure).

   <servlet>
      <servlet-name>HelloWorld</servlet-name>
      <servlet-class>com.liferay.portal.kernel.servlet.PortletServlet</servlet-class>
      <init-param>
         <param-name>portlet-class</param-name>
         <param-value>org.alfresco.web.portlet.ProxyPortlet</param-value>
      </init-param>
      <load-on-startup>0</load-on-startup>
   </servlet>
   <servlet-mapping>
      <servlet-name>HelloWorld</servlet-name>
      <url-pattern>/HelloWorld/*</url-pattern>
   </servlet-mapping>

You can place these two definitions anywhere within the top-level <web-app> element, but for consistency I always try to add them next to the existing <servlet> and <servlet-mapping> definitions.
Now you’ve done all you need to do to configure the scripts, we can move onto configuring the matching portlet definition which will be picked up by Liferay.
In the same WEB-INF directory where you modified web.xml you should find a file named portlet.xml, to which we add our new definition.

   <portlet>
      <description>Hello World</description>
      <portlet-name>HelloWorld</portlet-name>
      <portlet-class>org.alfresco.web.portlet.ProxyPortlet</portlet-class>
      <init-param>
         <name>viewScriptUrl</name>
         <value>/page/test/hello-world</value>
      </init-param>
      <supports>
         <mime-type>text/html</mime-type>
         <portlet-mode>VIEW</portlet-mode>
      </supports>
      <portlet-info>
         <title>Hello World</title>
         <short-title>Hello World</short-title>
      </portlet-info>
      <security-role-ref>
         <role-name>administrator</role-name>
      </security-role-ref>
      <security-role-ref>
         <role-name>guest</role-name>
      </security-role-ref>
      <security-role-ref>
         <role-name>power-user</role-name>
      </security-role-ref>
      <security-role-ref>
         <role-name>user</role-name>
      </security-role-ref>
   </portlet>

Add this right after the existing <portlet> definitions (which if you look at further it should be obvious define the three Doclib portlets) and save your changes.
Getting these details right is crucial if you’re deploying your own web scripts, so a couple of notes on this are probably useful.

  1. The contents of the <portlet-name> element must match the name of the servlet mapping you have defined in web.xml
  2. The viewScriptUrl parameter must match the URL of your web script, with a prefix of /page added to the beginning (note that in 3.2r the web app context path was also required in the URL, but this now causes an error if supplied)

Lastly you should add the portlet to the two Liferay-specific configuration files in WEB-INF to ensure that authentication is handled correctly and also that the portal appears in the correct category in Liferay’s Applications menu.
In liferay-portlet.xml add the following definition after the existing <portlet> elements

   <portlet>
      <portlet-name>HelloWorld</portlet-name>
      <user-principal-strategy>screenName</user-principal-strategy>
   </portlet>

In liferay-display.xml, add the following within the existing <category> element – it should be obvious that this is adding your portlet to the ‘Alfresco’ category.

<portlet id="HelloWorld"></portlet>

You’ll need to restart Liferay to get it to pick up the new portlet, and for Share in turn to load the additional web script. Once it’s finished loading you should be able to follow the configuration steps in the Doclib Portlet guide to walk you through adding it to a page.
The example is basic, but shows how you can add a web script as a portlet, with a small amount of personalisation based on the identify of the user.
It’s possible to add more complex web scripts, for example to load data from the Alfresco repository or other back-end data sources, but as Luis points out you should be careful how you render any hyperlinks within your scripts, to ensure that they are portal-safe.

To make sure that your URLs are correctly generated, please use the “scripturl()” function in your Freemarker templates to wrap them:
<a href=”${scripturl(url.serviceContext + “/sample/cmis/repo”, false)}”>CMIS Repository</a>

You can download the web script files used in this example in JAR format, which you can extract using any unzip program into the directories specified above (or even easier – simply drop the JAR file itself into Liferay’s tomcat-x.x.x/shared/lib folder).

Share Import-Export 1.1 released

The v1.1.1 release of Share Import-Export has been up for a few days now, but I wanted to summarise some of the changes in the new version.
The most significant addition is support for importing and exporting security groups in JSON format, via the new import-groups.py and export-groups.py scripts.
As well as this the import-users.py script has been made slightly more flexible, with the addition of a --users argument to allow you to import just a few users from a larger set. Since the sample data contains a large number of users that are used across all the different sample sites, you can now import just the users you need for a particular site.
As well as these functional improvements I’ve started cleaning up the code internally, an area I intend to focus a little more on over the next few weeks. For now I’ve just cleaned up the docstrings within each script, and updating the --help flags to re-use the usage information in there.
Last but not least, I should thank Dick from Formktek for reporting an issue with the user export script, which was causing some exported profile images to become corrupted when saved.
Beyond a few more tidy-ups the code is almost where I want it to be within the current constraints of the repository. But there have been a couple of ideas suggested for future uses of the scripts, so if there’s a particular purpose you think the scripts could have or you just want to share your experiences, please leave a comment below.