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.
Awesome post! Thanks again!
Great post and very useful!
Thanks for the awesome sample Jeff, this definitely gives me a good starting point.
I’m a bit confused as to how you attach your additional properties to the out-of the-box person type though (maybe I’m missing something?).
I addition to adding the additional properties to the user profile in Share, we also need some of the properties to be set via LDAP/AD sync, as well as some by an automated script that will pull them in from an external user directory database.
I have created an aspect for the additional properties but I’d like to make my new aspect mandatory for the cm:person type.
Any suggestions on the best way to accomplish this?
Thanks
Darryl,
Attaching the aspect to the person object is going to depend on the specific situation. I’ve had some projects where the creation of new accounts was automated and, in part, implemented by a web script. So we just attached the aspect in code when we created the accounts. You could edit the out-of-the-box model file to make the aspect mandatory. But I’d only do that as a last resort. In your case, you don’t have a single mechanism for creating users, so the “do it when you create the users” approach won’t work. Instead, you might want to create a behavior. The behavior can bind to the onCreateNode policy of cm:person. Your code can check for the presence of the aspect and add it if it isn’t there.
Jeff
Thanks Jeff!
After reading your suggestions and thinking about it a bit more, I see that using mandatory aspect on cm:person would be a bad idea (it doesn’t apply to external users, for one).
Since organizational users will always come from the Active Directory sync, it makes sense to just attach the aspect there during that process, as you said.
I’m definitely starting to see the flexibility aspects gives you in Alfresco.
Best Regards,
Darryl
I’m about to try this with 4.0.d, any tips. I’ll report back soon.
thanks, yet again, Jeff
cheers
chris
Hi Jeff,
The sample works with the Alfresco installer version. But when I apply it with my built-from-scratch Alfresco (4.0.1), the server says that it didn’t find where the sc-profile.js is. I guess it is because of checksum dependencies in Surf (http://blogs.alfresco.com/wp/ddraper/2012/03/06/checksum-dependencies-in-surf/). Do you have any workaround for this ?
Thanks in advance
Michael,
I would be shocked if that were the cause of the issue for a couple of reasons. First, that blog post mentions that the checksum feature hasn’t been added to any release–it is only in head. You appear to be using 4.0.1 Enterprise. Second, that feature helps by caching JavaScript files. The sc-profile.js file is a new, custom JS file, so if this feature were in place and if the reference were changed to leverage it, the file would simply be cached.
I haven’t tested the code against 4.0.1 Enterprise so I’m not sure what the problem is off-hand. I suspect that the problem is that the example was written for 3.4.d Community and that there have been enough changes between that release and the one you are using to cause an issue.
Chris, another poster on this thread, said they were going to try this on 4.0.d so it will be interesting to see how that goes. Whatever changes have to be made there to get it to work on 4.0.d will likely have to be made to support 4.0.1 Enterprise.
Jeff
Hi Jeff,
Thanks for a very useful tutorial… really helpful.
I’m very new to Alfresco and the problem I’m having here related to custom properties (meta-data) for documents
This is what I want: custom fields can be added on the fly for each space, so that different spaces can have different set of meta data for its document.
I’m not sure if you can do such things with Alfresco? Would you please provide me some advise?
Regards,
Hung
Hung,
You can add custom fields to a space. You can do that be either extending the cm:folder type with your own type that contains the custom fields or by creating an aspect with the custom fields and then applying that aspect to the folder. Either way, the properties will be stored with the folder. Documents can also have custom properties by using the same methods: Either extend cm:content with your own custom type or create an aspect and apply it to the document.
If you want to learn more about creating and configuring custom types, take a look at this tutorial.
Jeff
Hi Jeff,
Thanks for your reply. I managed to modify the metadata using XML config, but in the end, you will have to restart tomcat to get all the changes work.
Is there anyway you can modify the meta data without the need of restarting server?
Thanks,
Hung
It would be nice to provide end-user some sort of forms so they can add custom content types / meta data directly. I’d be desperate for something like that
Thanks,
Hung
Yes, those are called “hot-deployed” or “dynamic” models. You basically check your content model and your web client configuration into the repository as if it were content. See the documentation.
Go to Alfresco Add-Ons and do a search for “model”.
It’s a shame I didn’t even know the existence of Alfresco Add-ons
You saved my day Jeff *Salute*
Hi Jeff,
Is there any chance you can make a sample for adding custom properties into site?
I’m trying to add a custom property field into a site. I noticed that there’s existing aspect for custom properties in the siteModel.xml file. Just wonder how can I save the custom properties in the create site / edit site form…
Really appreciate your help.
Regards,
Hung
Hi Jeff,
I’m dealing with the problem that I want alfresco share to remember login , so after check “Remember me” checkbox and login successfully, user doesn’t have to log in the next time. Unfortunately, I couldn’t find any clue about this. Could you please give me some ? 🙂
Regards,
Michael
Hi Jeff,
Can you please share the Zip of all the code file changes of the same ?
As I have not implemented the same earilar and want to implement the same now.
Request you to share the ZIP of all files changes again,Please.
Thanks!
-Nirvan
Nirvan,
The code is linked to in the blog post.
Jeff
Hi Jeff,
hope you accept an other reply to this post from february. I migrated your code to a maven project and created an amp for repo stuff and an jar for the share extensions. The gui is working fine but unfortunatelly the persistence is not working. I get following exception:
…
Caused by: java.lang.NoSuchMethodError: org.springframework.extensions.webscripts.json.JSONWriter.startObject()V
at de.ppi.share.PpiUserFactory.saveUser(PpiUserFactory.java:66)
at org.alfresco.web.site.SlingshotUser.save(SlingshotUser.java:55)
at org.springframework.extensions.webscripts.ScriptUser.save(ScriptUser.java:317)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
…
Do you have an idea for me where to search the problem?
Hi Jeff,
I managed to complete this tutorial for Alfresco Community 4.0.b and I have one question.
The newly added aspect to the profile in Share is valid only for Share, am I wrong? If I want to add an aspect to the effective Content model I have to overwrite the orginal CM with an entire custom one I guess…
In my case I would like to add a sort of chief relationship (for an employee I want to associate a cm:person as *:chief), is there a way to easily select the person in the same way we select the bpm:assignee in the review workflows?
Thanks for your blog and your articles,we’re waiting for a new Developer Book!
Hi Jeff,
I’ve followed these steps on alfresco 4e community, but it caused an issue for my installation. We had been using NTLM auth over ldap without issue, but after deploying and restarting alfresco I am no longer logged in with my domain credentials. User’s are displayed the login page and catalina.out reports: Exception from executeScript – redirecting to status template error: 09170248 Guest authentication not supported
Users can still enter their details to login manually. Do you know what may have caused this?
You should post your issue in the Authentication, LDAP & SSO forum, which lives here: https://forums.alfresco.com/en/viewforum.php?f=57
Jeff
Hello Jeff,
Thanks you very mutch or your post.
I am new with Alfresco and would like to add 2 properties to a person. I do this by following your sample.
Unfortunetly there is no property displayed in share.
I do have any error.
I am using Alfresco 4.1.1. Could give me an idea ?
Thanks in advance,
Calavero.
Yeah, have done but I kind of assume I won’t get any responses. I reckon what’s going to happen here is I will revert the changes I made and we will keep these additional details outside Alfresco, it seems like a whole lot more trouble than it’s worth. I certainly hope that this is a simpler process in the future, more similar to the process to extend the content type.
Chris,
I agree that we can make it easier to extend the person object.
Jeff
Calavero,
I have not tried extending the person object with 4.1.1. I may have some time to do this after DevCon.
Jeff
Hello,
We have added the custom aspects and fields in alfresco share, but we are not able to fetch these property values in the drupal front end. Any help on this?
Thanks
Varun
Drupal? Are you using CMIS for the integration? If so, CMIS can’t deal with user objects.
Jeff
Hello,
Do you know how to extend Person Properties in Alfresco Community 4.0.2?? I’ve read this tip, but it doesn’t work in mine.
Thanks In Advance.
Very good!
Hi Jeff,
This is a very good post. Right in time as I was looking on how to extend the cm:person with custom properties. I have a requirement where a created user can have an expiration (more of a temporary account). But I believed this is not currently supported by Alfresco? I am using Alfresco Community 4.2c. I am planning to add an aspect to cm:person with properties which determines if the user account expires and on what date it will expire. I plan to disable or maybe delete the user by using a custom scheduled action. Is this a good approach? or can you give insights to some other good approach?
Thanks in advance!
Bernie
Hi Jeff,
Thank you for such a wonderful and time-saving demonstration! I can confirm that your customization works beautifully on Alfresco Enterprise 4.0.2.9. For anyone reading, just follow the example at https://ecmarchitect.com/images/articles/alfresco-people/someco-people.zip
One caveat however… your Eclipse/IDEA project must include the alfresco-share-4.0.2.9.jar library from the SDK, since it contains the SlingshotUserFactory class needed to extend cm:person. This one bit me until I figured it out.
One question: is there a similar example for adding the extended cm:person fields to the admin-console in Share? If not, can you provide a roadmap of how this could be done?
Thanks again and keep up the good work!
Hello Jeff,
I have updated the source code for this using Alfresco SDK 2.2 and Alfresco 5.1.
You may find the source code [here](https://github.com/sujaypillai/someco-people/archive/1.0.zip)