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:
- Extend org.alfresco.web.site.SlingshotUserFactory with your own Factory class
- In share-config-custom, override the defaults, user-factory element with a pointer to the new user factory bean
- Override Alfresco’s profile.js with your own and extend the Alfresco.UserProfile component.
- 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.
- 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:
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.