« Older Entries Subscribe to Latest Posts

9 May 2012

Take the 2012 Alfresco Community Survey and Win $250

Posted by jpotts. No Comments

It’s that time again, folks. Time to see how we did over the past year and what corrections we need to make in the year ahead to keep the Alfresco community on track.

Whether you are an Enterprise subscriber or someone who works with Community Edition, I need as many people in the ecosystem as possible to take the survey.

Why bother? Because we care what you have to say. Seriously. Many of the things we’ve done in the community over the past year have been a direct result of this survey. You told us, we listened, we executed. Now it is time to find out how effective that execution was and to see what we need to do for the coming year.

So please do take 15 minutes to tell us how we’re doing. And if the “help us help you” reason isn’t enough, two lucky winners will walk away with $250 Amazon Gift Certificates.

You have until June 15 to take the survey.

Thanks ahead of time for your feedback and good luck!

8 May 2012

Alfresco Example: Share Dashlets that Retrieve Data from the Repository

Posted by jpotts. No Comments

If you need to learn how to write an Alfresco Share dashlet, hopefully you’ve already worked through the Hello World dashlets in the Share Extras project on Google Code. The rest of the dashlets in that project are either “mash-up” style dashlets that read data from third-party sites or dashlets that work with data from the Alfresco repository tier, but are of moderate to high complexity. What I think is missing is a dashlet that goes one small step beyond Hello World to show how to read and display a simple set of data from the repository tier. In this post I show you how to do just that.

I created the example I’m going to walk you through in response to a question someone posted in the forum. They asked, “How can I write a dashlet that will show basic metadata from the most recently-modified document in a given folder?”. I think this is something we haven’t explained to people–we show Hello World and we show dashlets from the other end of the spectrum, but nothing to illustrate this basic pattern. So I wrote a quick-and-dirty example. Fellow forum user, RikTaminaars, also got in on the act, making the dashlet configurable, which I’ll show in a subsequent post.

In this post, I’ll create the most basic implementation possible. The result is a simple dashlet that reads a path from a configuration file, asks the repository for the most recently modified document in that folder, then displays some basic metadata. In my next post, I’ll add to it by making the folder path configurable within the user interface.

Developer Setup

First, a bit about my setup. I’m running Alfresco 4.0.d Community, WAR distribution, Lucene for search, Tomcat application server, and MySQL for the database. I’m using Eclipse Indigo, but this implementation requires no compiled code. For organizing the project files I used the Sample Dashlet project structure from Share Extras. I’m using the Share Extras Ant build script to deploy my code from my project folder structure to the Alfresco and Share web applications.

When I’m doing Share customizations I use two Tomcats–one for the repository tier and one for the Share tier. This helps me avoid making assumptions about where my Alfresco and Share web applications are running and it speeds up my development because my Share Tomcat restarts very quickly. To get the Share Extras build script to work with a two Tomcats setup, I’ve added the following to a build.properties file in my home directory:

tomcat.home=/opt/apache/tomcat/apache-tomcat-6.0.32
tomcat.share.home=/opt/apache/tomcat81/apache-tomcat-6.0.32
tomcat.share.url=http://localhost:8081

Now the build script will know to put the deployed code in each of my Tomcat servers.

The Data Web Script/Presentation Web Script Pattern

The Alfresco repository runs in a web application called “alfresco” while the Share user interface runs in a separate web application called “share”. Each of these two web applications has its own web script engine. If you aren’t familiar with web scripts, take a look at this tutorial, then come back, or just accept the high-level notion that web scripts are an MVC framework used to bind URLs to code and that web scripts can run on the repository tier as well as the Share tier.

Share dashlets–the “boxes” of content that display in the Share user interface–are just web scripts that return HTML. In fact, everything you see in Share is ultimately a web script. When a dashlet needs to display data from the Alfresco repository, it makes a call over HTTP to invoke a web script running on the repository tier. The repository tier web script responds, usually with JSON. The dashlet gets what it needs from the JSON, then renders outputs HTML to be rendered as part of the page. Because the repository tier web script responds with raw data, you may see these referred to as “data web scripts”.

In the previous paragraph, I was purposefully vague about where the request to the repository tier is made. That’s because there are two options. The first option, and the one we’ll use in this example, is to make the call from the dashlet’s web script controller. This might be called “the server-side option” because once the dashlet’s view is rendered, it has all of the data it needs–no further calls are needed.

The second option is to make AJAX calls from the client browser. To avoid cross-site scripting limitations, these calls typically go through a proxy that lives in the Share application, but their ultimate destination is the repository tier.

Two tier web scripts

You may be wondering about the details of making these remote connections. It’s all taken care of for you. Regardless of whether you make the remote invocation of the repository web script from the Share tier or through AJAX in the browser, all you need to specify is the URL you want to invoke and the framework handles everything else.

Show Me the Code: Repository Tier

Let’s walk through the code. I’ll start with the repository tier. Recall that the requirements are to find the most recently modified document in a given folder and return its metadata. There may be out-of-the-box web scripts that could be leveraged to return the most recently modified document, but this is actually very simple to do and I don’t want to have to worry about those out-of-the-box web scripts changing in some subsequent release, so I’m implementing this myself.

Using the Share Extras project layout, repository tier web scripts reside under config/alfresco/templates/webscripts. The best practice is to place your web script files in a package structure beneath that, so I am using “com/someco/components/dashlets” for my package structure. Yours would be different.

The first thing to think about is what the URL should look like. I want it to be unique and I need it to accept an argument. The argument is the folder path to be searched. For this example, my URL will look like this:

/someco/get-latest-doc?filterPathView={filterPathView}

If you’ve worked with web scripts, you know that a “path” pattern could be followed instead of a “query string” pattern but it doesn’t really matter for this example. The descriptor, get-latest-doc.get.desc.xml, declares the URL and other details about authentication and transaction requirements.

The controller performs the search and populates the model with data. This is a GET, so the controller is named get-latest-doc.get.js. Look at the source for the complete listing–I’ll just hit the high points.

First, I grab a handle to the folder represented by the path argument:

var folder = companyhome.childByNamePath(args.filterPathView);

Then I use the childFileFolders() method to get the most recently modified file and stick that in the model:

var results = folder.childFileFolders(true, false, 'cm:folder', 0, 1, 0, 'cm:modified', false, null);
model.latestDoc = files[0];

Obviously, I could have used a search here, but this method is quite handy. It must be new (thanks, Rik!).

The view then takes the data in the model and returns some of the metadata as JSON:

<#macro dateFormat date>${date?string("dd MMM yyyy HH:mm:ss 'GMT'Z '('zzz')'")}</#macro>
<#escape x as jsonUtils.encodeJSONString(x)>
{
"nodeRef": "${latestDoc.nodeRef}",
"name": "${latestDoc.properties.name}",
"title": "${latestDoc.properties.title!}",
"description": "${latestDoc.properties.description!}",
"created": "<@dateFormat latestDoc.properties.created />",
"modified": "<@dateFormat latestDoc.properties.modified />"
}
</#escape>

Note the exclamation points at the end of the title and description. That will keep the template from blowing up if those values are not set.

That’s all there is to the repository tier. If you want to add additional metadata, custom properties, or data from elsewhere in the repo, it is easy to do that.

At this point you should be able to deploy (run ant hotcopy-tomcat-jar, for example) and test the repository tier web script by pointing your browser to: http://localhost:8080/alfresco/s/someco/get-latest-doc?filterPathView=/Some/Folder/Path

Show Me the Code: Share Tier

Okay, the back-end is ready to return the data I need. Now for the front-end. The Share Extras project structure puts front-end web scripts in config/alfresco/site-webscripts so following a similar pattern as I did for the repository-tier web scripts, I put my share-tier web scripts into the site-webscripts folder under com/someco/components/dashlets.

The descriptor, get-latest-doc.get.desc.xml, declares a URL for the dashlet and specifies the “dashlet” family. This will make the dashlet appear in the “add dashlets” menu for both the global dashboard and the site dashboard.

I want to make the folder path configurable, so I created get-latest-doc.get.config.xml and used it to specify a title for the dashlet and the default folder path. I’ll read in this configuration from the controller.

As I mentioned, we’re doing everything server-side in this example, so the controller needs to call the web script I deployed to the repository tier to retrieve the JSON. Then it can put that object into the model and let the view format it as it sees fit. The controller lives in get-latest-doc.get.js and starts out by reading the configuration XML:

Then it uses the built-in “remote” object to invoke the repository tier web script and puts the result into the model:

Note that the URL starts with my web script’s URL–it includes nothing about where to find the Alfresco repository. That’s because the “end point” is declared in Share’s configuration (to be precise, it is actually Surf configuration, the framework on which Share is built) and the remote object uses the “alfresco” endpoint by default. I don’t see it used very often, but you can actually define your own end points and invoke them using the remote object.

The last part of this example is the HTML markup for the dashlet itself. The first half of get-latest-doc.get.html.ftl is boilerplate that has to do with the dashlet resizer. For this example, the length of the list is static–it will only ever have one entry. So the resizer is kind of overkill. The bottom half is where the markup for the document’s metadata lives:

If you’ve already worked with web scripts, you know that get-latest-doc.get.head.ftl is used to place resources into “<head>”. In this case, that is a CSS file used to style our dashlet and client-side JavaScript used by the resizer. The strings used in the dashlet are localized through the get-latest-doc.get.properties file.

Test It Out

You should be able to test this out yourself by creating a folder anywhere in the repository, adding one or more files to the folder, specifying that folder path in the get-latest-doc.get.config.xml file, and then using “ant deploy hotcopy-tomcat-jar” to deploy the customizations to the alfresco and share web applications. You’ll need to restart Tomcat to pick up the new JAR (both Tomcats if you are running two). Then, login and click “Customize Dashboard” to add the “Get Latest Document” dashlet to your dashboard. It should look something like this:

Screenshot: Get Latest Document Dashlet

Summary

This is a simple example, but it is powerful because it is the same pattern used throughout Share: A dashlet needs data from the repository tier, so its web script controller uses the “remote” object to call a web script on the repository tier. The repository tier web script returns JSON which the Share tier web script then formats into a nice looking dashlet.

In my next post, I’ll show how to make the folder path configurable, so that you can change it at run-time with a folder picker in the Share user interface instead of editing the config XML.

3 May 2012

New Activiti Release includes Designer Plug-in Enhancements

Posted by jpotts. 1 Comment

Did you know there’s a new release of Activiti out? Okay, it has been out since March but I’m just now getting around to saying something about it. I haven’t given the entire thing a thorough evaluation, but if you are using the Activiti Designer Eclipse plug-in, you’ll be happy to know that you don’t have to fool with two files for each process definition any longer (three files, if you count the PNG). Instead of a .activiti file and a .bpmn20.xml file, there is just a single .bpmn file.

The new Designer also supports modeling sub-processes. And, it is easier to work with boundary events than it was before.

If you have existing Activiti process definitions, you can open your old .bpmn20.xml files and save them as .bpmn files. Then you can delete your .activiti and .png files.

The version of Activiti embedded in Alfresco 4.0 (Community and Enterprise) is 5.7. I’m assured by the development team that processes edited with version 5.9 of the Designer will continue to work with 5.7. However, there may be some items on the palette that are not supported in older Activiti versions.

One thing to note about this release of the Eclipse plug-in: It no longer runs with Eclipse Helios. You’ll have to upgrade to Indigo.

27 Apr 2012

Alfresco security alert

Posted by jpotts. No Comments

Both Alfresco Enterprise and Community Edition users need to pay attention to the security alert that went out last night. In a nutshell, two serious security issues (ALF-13721, ALF-13726) that could be exploited in order to gain unauthorized access to your repository and the content within it have been discovered and addressed.

ALF-13721 refers to an issue that the SOLR API webscripts can be executed without authentication. If you are running Alfresco 4, this affects you, even if you have not installed or configured SOLR. The issue is addressed in 4.0.1 Enterprise. A hotfix is available for 4.0.

ALF-13726 is about exploiting the XSLT engine’s ability to run arbitrary Java classes which could be used to grant someone access to the repository. This one affects all versions of Alfresco. This issue will be addressed in 3.4.9. A hotfix is available.

Community Edition users should be able to patch these issues themselves using information provided in the Jiras and forum post referenced above. The fixes will be incorporated into the next Community release.

19 Apr 2012

How to suggest or propose a DevCon 2012 talk

Posted by jpotts. No Comments

If you want to give a talk at DevCon, here are your options:

  • Read the call for papers, then submit a proposal for a traditional session no later than May 19
  • Come to the conference and sign up for a Lightning Talk
  • Come to the conference and participate in a Birds-of-a-Feather session

If you have an idea for a session but you don’t want to speak, reply to this thread in the forums with your idea and maybe it will inspire someone else to give the talk.

17 Apr 2012

Alfresco DevCon 2012: San Jose & Berlin

Posted by jpotts. No Comments

Last week I announced that Alfresco DevCon 2012 will be in Berlin and San Jose. We’ll be at the Berlin Hilton November 5, 6, & 7 and at the San Jose Marriott & Convention Center November 13, 14, & 15. Eagle-eyed readers who saw the announcement last week will note that the Berlin date has changed. The DMS Expo conference in Stuttgart conflicted with our dates so we’re moving to give everyone the maximum opportunity to Experience DevCon Awesomeness.

In both cities, the first day of the conference is an optional training day. We’re still working out exactly which classes will be offered on the training day, but we are increasing capacity this year due to popular demand.

Like last year, the main conference days will feature keynotes from Alfresco leadership, some great sessions from Alfresco Engineers, partners, and other members of the community, and plenty of opportunities for networking.

I’m finalizing tracks right now. As soon as I’m done, I’ll post the call for papers. I expect you to unleash a flood of outstanding conference submissions.

If you need some inspiration, take a look at the DevCon 2011 presentations on slideshare.

I typically post DevCon related news here but you might also want to follow the DevCon blog as well.

2 Apr 2012

Alfresco forum users on a map & some forum stats for March

Posted by jpotts. 1 Comment

I think this is kind of cool. It’s a map that shows the Alfresco English-language forums users.

(Click to enlarge)

I love how global our community is! If your location isn’t represented, it is because either I couldn’t look up your location by IP address or you don’t have your location set in your forum profile. Telling us a bit about who you are is useful beyond map-making–it can help with event planning, for example. And maybe you’ll find someone nearby with similar interests. So why not update your location while you’re thinking about it?

Looking at the map, I guess my biggest question is: What gives, Iceland? You keeping all of that good Alfresco knowledge to yourself or what?

While I’m on the subject, I should probably mention that the top users in terms of number of posts for March were (in alphabetic order):

  • AFaust
  • Andy
  • Ashex
  • BillyBoy
  • MikeH
  • billerby
  • jordiv
  • jpotts
  • mitpatoliya
  • mrogers

Thank you!

And, if you are looking to help make a dent in unanswered posts, the top forums in descending order of unanswered posts are:

  1. Alfresco Share
  2. Configuration
  3. Alfresco Share Development
  4. Installation
  5. Alfresco Discussion
  6. Authentication, LDAP, & SSO
  7. Repository Services
  8. Development Environment
  9. Web Content Management
  10. Workflow

Unanswered posts were below average in February and March, which is great, but there is still room for improvement.

7 Mar 2012

Tip: How to move an Alfresco category

Posted by jpotts. No Comments

Alfresco has a category hierarchy that can be used to categorize content. Unlike tags, which are not in a hierarchy and can be created by anyone, categories must be managed by an administrator. But even an administrator cannot move a category from one parent to another through the user interface. When it is time to reorganize your categories, how do you do it?

It’s actually pretty easy to do this with code. Your first thought might be, “Well, a category is a node and server-side JavaScript can work with nodes, so I’ll just write a quick script to do the move,” and who could blame you–that’s a well-reasoned line of thinking. But if you look at the source for the current JavaScript API ScriptNode object’s “move” method, you’ll see that it assumes that the association it is creating is “cm:contains”. Categories are associated with an association called “cm:subcategories”, not “cm:contains”. So, at least in this release, JavaScript can’t help us.

Luckily, Alfresco’s Java API is up to the task. When you call the NodeService’s moveNode method you have full control over the new relationship that gets created.

For stuff like this it is often handy to whip up a little Java-backed web script. All the web script needs is the source node reference that needs to be moved and a target node reference to move the source node reference to. Here’s the class with debug and parameter checking removed:

public class MoveCategory extends DeclarativeWebScript {

  // Dependencies
  private NodeService nodeService;

  @Override
  protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) {

    final String sourceNodeRefString = req.getParameter("sourceNodeRef");
    final String targetNodeRefString = req.getParameter("targetNodeRef");

    // snag the nodes
    NodeRef sourceNodeRef = new NodeRef(sourceNodeRefString);
    String sourceName = (String) nodeService.getProperty(
                                   sourceNodeRef,
                                   ContentModel.PROP_NAME);
    NodeRef targetNodeRef = new NodeRef(targetNodeRefString);
    String targetName = (String) nodeService.getProperty(
                                   targetNodeRef,
                                   ContentModel.PROP_NAME);

    // move the source node to the target
    nodeService.moveNode(sourceNodeRef,
                         targetNodeRef,
                         ContentModel.ASSOC_SUBCATEGORIES,
                         QName.createQName(
                           NamespaceService.CONTENT_MODEL_1_0_URI,
                           sourceName));

    // set up the model
    Map<String, Object> model = new HashMap<String, Object>();
    model.put("sourceNodeRef", sourceNodeRefString);
    model.put("sourceName", sourceName);
    model.put("targetNodeRef", targetNodeRefString);
    model.put("targetName", targetName);

    return model;
  }

  public void setNodeService(NodeService nodeService) {
    this.nodeService = nodeService;
  }

}

If you need to see how to wire up the web script with Spring configuration, or you want to see the rest of the web script files (like the descriptor & view), you can take a look at this zipped up Eclipse project.

I should mention that in my web script descriptor, I configured the web script to require an authenticated user, but I set it to run as admin. That gives non-admin users the ability to move categories around using this web script. You may or may not want to do that.

Also, because this is just an example, I’m using the zip overlay method of deployment. For production, you should be using AMPs.

For more Java-backed web script examples, see this wiki page. And if you would prefer to use Maven to develop your Java-backed web scripts, take a look at this project on Google Code.

29 Feb 2012

Thoughts on the Alfresco forums

Posted by jpotts. 3 Comments

Back in 2009 I wrote a post called, “The Alfresco forums need your help.” It was about how I happened to come across the “unanswered posts” page in the Alfresco forums and noticed, to my horror, that it was 40 pages long. I later realized that the site is configured to show no more than 40 pages so it was likely longer.

Now that I’m on the inside I’ve got access to the data. As it turns out, as of earlier this month, in the English forums we had a little over 1100 topics created over the past year that never got a reply. That represents about 27% of all topics created for that period.

Last year I ran a Community Survey that reported that 55% of people have received responses that were somewhat helpful, exactly what they were looking for, or exceeding expectations. A little over 10% received a response that wasn’t helpful. About 34% said they never saw a response. If you look at the actual numbers for the year leading up to the survey, there were about 1500 topics created that never got a reply, which is again about 28% of all topics created for the same period.

That day in 2009 I suggested we start doing “Forum Fridays” to encourage everyone to spend a little time, once a week, helping out in the forums. I kept it up for a while. The important thing for me was that even if I didn’t check in every Friday, I did form a more regular forum habit. It felt good to see my “points” start to climb (you can see everyone’s points on the member list) and I started to feel guilty when I went too long without checking in.

Since joining Alfresco I’ve been in the forums more regularly. In fact, this month, I decided to make February a month for focusing on forums. I spent a significant amount of time in the forums each day with a goal of making a dent in unanswered posts. I also wanted to see if I could understand why posts go unanswered.

Some topics I came across were unanswered because they were poorly-worded, vague, or otherwise indecipherable. I’d say 5% fit this category. More often were the questions that were either going to require significant time reproducing and debugging or were in highly-specialized or niche areas of the platform that just don’t see a lot of use. I’d say 20% fit this category. These are questions that maybe only a handful of people know the answer to. But at least 50% or maybe more were questions a person with even a year or two of experience could answer in 15 minutes or less.

Alfresco is lucky. Our Engineering team spends significant time in the forums. The top posters of all time–Mike Hatfield, Mark Rogers, Kevin Roast, Gavin Cornwell, Andy Hind, David Caruana, Derek Hulley–are the guys that built the platform. Somehow they manage to do that and consistently put up impressive forum numbers. We also have non-Alfrescans that spend a lot of time in the forums racking up significant points. Users such as zaizi, Loftux, OpenPj, savic.prvoslav, and jpfi, just to name a few, are totally crushing it. It isn’t fair or reasonable for me to ask either of these groups to simply spend more time in the forums. And, while I have sincerely enjoyed Focus on Forums February, I’m not a scalable solution. Instead, I’d like to mobilize the rest of you to help.

I think if we put our minds to it, we should be able to address every unanswered post:

  • Questions that are essentially “bad questions” need a reply with friendly suggestions on how to ask a better question.
  • Time-consuming questions need at least an initial reply that suggests where on docs.alfresco.com, the wiki, other forum posts, or blogs the person might look to learn more, or even a reply that just says, “What you’re asking can’t easily be answered in a reasonable amount of time because…”. People new to our platform don’t know what is a big deal and what isn’t, so let’s explain it.
  • Highly-specialized or niche questions should be assigned to someone for follow-up. If you read a question and your first thought is, “Great question, I have absolutely no idea,” your next thought should be, “Who do I know that would?”. Rather than answering the question your job becomes finding the person that does know the answer. Shoot them a link to the thread via email or twitter or IRC. Some commercial open source companies I’ve spoken to about this topic actually assign unanswered posts to Jira tickets. That’s food for thought.
  • Relatively easy questions have to be answered. Our volume is manageable. We tend to get about 400 new topics each month with 100 remaining unanswered, on average. With a company of our size, with a partner network as big as we have, with as many community members as there are in this world, I see no good reason for questions of easy to medium difficulty to go without a reply.

So here are some ideas I’ve had to improve the unanswered posts problem:

  • Push to get additional Alfrescans involved in the forums, including departments other than Engineering.
  • Continue to encourage our top posters and points-earners to keep doing what they are doing.
  • Identify community members to become moderators. Task moderators with ownership of the unanswered post problem for the forums they moderate. This doesn’t mean they have to answer every question–but it does mean if they see a post that is going unanswered they should own finding someone who can.
  • Continue to refine and enhance forums reporting. I can post whatever forums metrics and measures would help you, the community, identify areas that need the most help or that motivate you to level up your forums involvement. Just let me know what those are.

What are your thoughts on these ideas? What am I missing? Please give me your ideas in the comments.

By the way, while I’m on the subject, I want to congratulate and thank the Top 10 Forum Users by Number of Posts for January of this year:

1. mrogers* 74
2. amandaluniz_z 36
3. MikeH* 30
4. jpotts* 25
5. fuad_gafarov 22
6. zomurn 21
7. Andy* 19
8. RodrigoA 16
9. ddraper* 16
10. mitpatoliya 16

As noted by the asterisk (*) half of January’s Top 10 are Alfresco employees.

And if you are looking for specific forums that need the most help in terms of unanswered posts, here are the Top 10 Forums by Current Unanswered Post Count (as of 2/16):

1. Alfresco Share 210
2. Configuration 169
3. Alfresco Discussion 89
4. Alfresco Share Development 85
5. Installation 82
6. Repository Services 54
7. Workflow 47
8. Development Environment 44
9. Web Scripts 44
10. Alfresco Explorer 40

I’ll post the February numbers next week, and will continue to do so each month if you find them helpful or inspiring.

27 Feb 2012

Tip: Adding your own properties to a person object in Alfresco 3.4

Posted by jpotts. 17 Comments

Someone in our IRC channel recently asked how to add custom properties to the cm:person object and then configure Alfresco Share to show those properties in Alfresco 3.4.d Community. I have seen this come up in the forums as well and have done this before so I thought I’d do a quick write-up to show you how I did it.

As most people who try to do this are quick to discover, the user profile does not leverage the Alfresco form service to render its form. And rather than getting the person object metadata from a “normal” data web script like it does for other types of nodes, the data is read from a Share tier Java object called AlfrescoUser and AlfrescoUserFactory. Those classes only know how to deal with out-of-the-box properties of cm:person, so while you are free to add your own aspects to objects of type cm:person, the custom properties defined within those aspects won’t be available to the profile form without some additional work.

Although somewhat annoying when you come across the problem for the first time, it is remedied relatively easily by sub-classing the AlfrescoUserFactory class with your own and extending the client-side Alfresco.UserProfile object. Then it is just a matter of tweaking the userprofile web script to show your properties.

Assuming you have already created an aspect that defines the custom properties you want to add to the person object, the steps to make those usable from within the Share web client are:

  1. Extend org.alfresco.web.site.SlingshotUserFactory with your own Factory class
  2. In share-config-custom, override the defaults, user-factory element with a pointer to the new user factory bean
  3. Override Alfresco’s profile.js with your own and extend the Alfresco.UserProfile component.
  4. Extend org/alfresco/components/profile/userprofile.get.html.ftl with your own that references the extended user profile component and includes fields and labels for your custom properties.
  5. Localize your custom properties.

I’ve whipped up a little example here. This example is known to work with Alfresco 3.4.d Community. You can use the same approach to implement this in other versions, but there have been some changes in this area across releases, so you probably will not be able to use the exact same code for different versions.

In my example, the fictitious company, SomeCo, wants to add the following fields to the person object:
- Birth Date (date field)
- Shirt Size (text field, constrained by a list)
- Significant Other (text field)
- Likes Neil Diamond (boolean for segregating employees into the two types of people in the world according to Bob Wiley: Those that like Neil Diamond and those that don’t).

Step 1. Extend org.alfresco.web.site.SlingshotUserFactory

In 3.4.d there are two methods you need to override: constructUser and saveUser. You can grab the source (it’s not in the source with the SDK or in Alfresco SVN–you’ll need the Spring Surf Web Scripts source) and have a look at that class and those methods to see if you can do the same for your version. If you are using 3.4.d Community you can just copy mine and modify it.

You’ll need to wire in the bean via Spring config. I put mine in custom-slingshot-application-context.xml.

Step 2. Point to the custom userfactory in Share config

Alfresco Share uses the form configuration to determine which user factory to use. So I override the default in share-config-custom.xml with a pointer to the bean declared in the previous step.

Step 3. Extend the client-side Alfresco.UserProfile component

Alfresco has a client-side JavaScript component called Alfresco.UserProfile that is used, among other things, to switch back-and-forth between read and edit mode. The onEditProfile method needs to know about my custom properties. So I created a new client-side component called SomeCo.UserProfile that extends Alfresco.UserProfile and replaces its onEditProfile method with my own. That client-side JavaScript lives in a file called “sc-profile.js”.

In order to get that client-side JavaScript file loaded, I must add a reference to the “userprofile” web script. So I copied userprofile.get.head.ftl from the OOTB location into the corresponding file path under web-extension, edited it, and added an “@script” entry for my script.

Step 4. Override the userprofile web script with new markup

Speaking of web scripts, that same userprofile web script builds the profile form, so I copied userprofile.get.html.ftl from the OOTB location into the corresponding location under web-extension and made a few changes. The first was to change out the reference to Alfresco.UserProfile to my custom profile, SomeCo.UserProfile. The profile data gets passed in as JSON so it must include the custom properties, so I added those. Then, I added markup used to display the custom properties in both read mode and edit mode.

Step 5. Localize the labels for the custom properties

The labels that display on the user profile form need to be localized. I created a somecoPeople.properties file under web-extension and then wired that in by overriding the webscripts.resources bean in custom-slingshot-application-context.xml.

That’s it. Once that’s done you can successfully set these properties by editing an existing profile.

Here is what it looks like when it is working:

Custom properties of cm:person showing up in Alfresco Share

You’ll note that I spent no time at all on the UI which is evident by requiring the user to enter the ISO8601 date time format (like 1976-07-04T00:00:00.000-05:00) instead of providing a nice calendar picker, not providing any sort of help text, and not doing any validation on any of the fields. It’s not that relevant to the topic (and I ran out of time).

Hope this helps. If you do the same thing for other Alfresco versions and can share what you did, please add a link in the comments. Maybe in future versions we’ll be able to do this through config.