Changes in Social Equity in Liferay 6.1

There have been some pretty interesting and important changes regarding Social Equity for Liferay 6.1. While some of the changes are conceptual and others are additional features, there is one thing that is very important: there has been a change of API.

The new equity system is now part of the social activity framework. This is not just a naming concept. As part of the change, several functionalities were moved to different services and the original Social Equity services were removed. The whole framework got its own XML descriptor (formerly activities were configured in resource actions descriptors) that can be used to define activities and everything else related to them. This new descriptor can be used to extend already configured activities and can be used in plugins as well.

The Goal of the New System

While the main goal of being able to measure participation and contribution in a communty hasn't changed, there are some differences how these values are created and maintained. The new social equity system is now part of a broader scoped social activity framework that is designed to log certain activities as well as provide numerical instruments to monitor actvities or simply to provide the means for statistical analysis. 

Activity Counters

The heart of the new system is the counter framework. These counters are defined for activites in the new liferay-social.xml. The basic concept is to have three types of counters: actor, asset and creator. The difference is the owner of the counter. An actor counter is linked to the user doing the activity, while the asset counter is linked to the asset the activity is being done on. Creator counters have a reference to the user that is the owner/creator of the asset the activity was done on.

This system provides the basis for an extendable metrics system for assets and users.

Statistical Periods

One of the biggest conceptual changes is the introduction of the counter period. Values no longer degrade, rather there is a configurable time interval where points are aggregated resulting in a "current" value for each of these periods. A total value is also maintained. This method suits the human thinking more than the former method of degrading values. We are more used to thinking in periods. We are used to having "employee of the month" or values projected to a certain year - such as balance sheets. 

Equity Counters

The old social equity scores are mostly still there. Fundamentally these values are just counters. Of course there are always those more equals among equals, so equity counters have some special treatment. In addition to the limit system that has been implemented for normal counters these counters have some other checks that for example guard against an asset owner building up its own asset's popularity and a result his or her own contribution score by doing certain actions on his or her asset. 

One of the equity counters has also been renamed. Formerly known as Information Equity, this counter is called now Popularity. The reason behind the change is that with the actions available in a normal portal it is very hard to really mark asset as informative. Chances are that people do certain things on assets they simply like. Whether they like them because they are infomative is a possibility but it is not certain. Also contribution to a community is not necessarily requires assets with a high informational value. Some of the sites just want to increase the time people spend there, or want to increase the pariticipation of their users and users spend as much time with assets they just like as with assets that provide information to them. Therefore the relation between the popularity counter (that is an asset counter and was formerly called Information Equity) and the contribution counter (formerly known as Contribution Equity, currently an actor counter) remained the same: whenever an asset receives popularity points, its owner gets the same points in contribution.

API changes

One of the most importart API changes is that the triggering of an equity action was moved to the social activity service. In fact, adding a social activity now triggers the new social equity service automatically, so you can simply call one of the addActviity() methods in SocualActivityLocalService and if things are configured and social equity is enabled for the group, everything will be fine. If the activity is configured to be logged, the social activity service will log it the same way it's been doing so far, so that it can appear in the activities portlet. Additionally it will call new SocialActivityCounterLocalService to trigger counter processing. 

To get the value of a counter (including participation and contribution values as they are handled as counters) you can use the fetchLatestActivityCounter() method of the SocialActivityCounterLocalService. There are additional helper methods to retrieve a list of counters by other criteria, but probably this is the most important method of the service.

Blogs
Great post Zsolt! Thanks! I had a question: for custom portlet, where exactly should liferay-social.xml be located? Do you have a sample .xml file? Would be great!
Hi Puj,

Just put it in WEB-INF. As for the sample file, check out the one that is in the portal if you can. You can find a lot of different settings in there.

Best,
Zs.
Thanks mate! I successfully added the activities. Now I am struggling with the new resource and asset methods. But I am almost there! ;) I hope a sample code would be available soon in KB, it will save lots of time
Hi Zsolt,

I was using below API in my Liferay 6.0 custom portlet for enabling the Social Equity on the group: -

SocialEquityGroupSettingLocalServiceUtil.updateEquityGroupSetting(group.getGroupId(), Group.class.getName(), 1,true);
SocialEquityGroupSettingLocalServiceUtil.updateEquityGroupSetting(group.getGroupId(), Group.class.getName(), 2,true);

After migrating my application to Liferay 6.1, I replaced the above 2 lines with below line: -

SocialActivitySettingLocalServiceUtil.updateActivitySetting(group.getGroupId(), Group.class.getName(), true);

But this has not helped me in enabling the Social Equity(Activity). Can u please point me into some direction? Thanks in advance.
Hi Nilesh,

You are using the right method, but the second parameter is the classNameId for the model you want to enable social activities for in the given group. In other words now you cannot enable/disable on the group level, you need to specify the model too.

I hope this helps.

Zs.
Thanks very much for reply.

But then does this mean that I have to call this API for every model? Bcoz apart from Blogs, Wiki, MB, I have my custom assets too on which Social Equity needs to be allocated.SocialEquityGroupSettingLocalServiceUtil.updateEquityGroupSetting(..) method in Liferay 6.0 was enabling all the assets on a given group. Any API providing same functionality?

Thanks again.
Yes, you need to call the method for each model.
Hi Zsolt
I was using user.getParticipationEquity() And user.getContributionEquity() to get users participation and contribution score in LR6.0. Now in LR6.1 How will i get users score?.is any equivalent service available here?.
Hi Mahendra,

As participation and contribution are handled as counters now, you can simply ask for them through the SocialActivityCounterLocalService. Use the fetchLatestActivityCounter(long groupId, long classNameId, long classPK, String name, int ownerType) method. ClassNameId for these counters is the classNameId of com.liferay.portal.model.User, the name is "participation" or "contribution" and the owner type is SocialActivityCounterConstants.TYPE_ACTOR for participation and SocialActivityCounterConstants.TYPE_CREATOR for contribution. The classPK is the userId. The returned counter will have a currentValue for the actual value for the current statistical period (by default the current month) and a totalValue.

I hope this helps.
Hi Zsolt
I want to add social equity on custom assets.i have configured liferay-social.xml for my assets But I am not getting participation and contribution for that.
can you give me some right direction?
please refer this post for deatails: http://www.liferay.com/community/forums/-/message_boards/message/12486137
Thanks
Mahendra
Hi Mahendra,

I have commented on the message boards.
Ho Zsolt,

I am trying to read the score of a user in a portlet and I am using this method:
long userClassNameId = ClassNameLocalServiceUtil.getClassNameId(User.class.getName());
SocialActivityCounter counter = SocialActivityCounterLocalServiceUtil.fetchLatestActivityCounter(scopeGroupId, userClassNameId,user2.getUserId(), "participation",SocialActivityCounterConstants.TYPE_ACTOR);
int pScore = counter.getTotalValue();//currentValue() for the actual value for the current statistical period (by default the current month)
counter = SocialActivityCounterLocalServiceUtil.fetchLatestActivityCounter(scopeGroupId, userClassNameId,user2.getUserId(), "contribution", SocialActivityCounterConstants.TYPE_CREATOR);
int cScore = counter.getTotalValue();
int totalScore = pScore+cScore;


The problem is, I strangely get a JasperException when calling the totalValue() method of the counter:
Stacktrace:
at org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:568)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:470)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.ja
va:72)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilter.doFilter(InvokerFilter.java:70)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:684)
at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:593)
at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:530)
at com.liferay.portlet.PortletRequestDispatcherImpl.dispatch(PortletRequestDispatcherImpl.java:316)
at com.liferay.portlet.PortletRequestDispatcherImpl.include(PortletRequestDispatcherImpl.java:105)
at com.liferay.util.bridges.mvc.MVCPortlet.include(MVCPortlet.java:366)
at com.liferay.util.bridges.mvc.MVCPortlet.include(MVCPortlet.java:382)
at com.liferay.util.bridges.mvc.MVCPortlet.doView(MVCPortlet.java:145)
at com.liferay.portal.kernel.portlet.LiferayPortlet.doDispatch(LiferayPortlet.java:211)
at com.liferay.util.bridges.mvc.MVCPortlet.doDispatch(MVCPortlet.java:318)
at javax.portlet.GenericPortlet.render(GenericPortlet.java:233)
at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:100)
at com.liferay.portal.kernel.portlet.PortletFilterUtil.doFilter(PortletFilterUtil.java:64)
at com.liferay.portal.kernel.servlet.PortletServlet.service(PortletServlet.java:93)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.ja

Do you know why this is happening? I am doing something wrong or is it a bug?

Cheers
Can you try to enclose the call in a try catch and print the stack trace so that we know what's happening?
Hi Zsolt,

I am still struggling with the configuration. I have a question: what is <counter> for? Is it optional? If I have a custom model called collection and I want to add social equity for adding a new collection, can I just call it <counter>user.collections</counter>? I left it out but then it is not being included in the User Statistics portlet. I am confused.
Here is my definition in liferay-social.xml:
<liferay-social>
<activity>
<model-name>org.fortiss.fb3.innovationRepository.model.Collection</model-name>
<activity-type>${org.fortiss.fb3.innovationRepository.social.CollectionActivityKeys.ADD_COLLECTION}</activity-type>
<language-key>ADD_COLLECTION</language-key>
<log-activity>true</log-activity>
<contribution-value>0</contribution-value>
<contribution-limit enabled="false" />
<participation-value>10</participation-value>
<participation-limit enabled="false"/>
</activity>

I left out the counter part.
maybe I should asset.activities in <counter> for custom models?
Hi Puj,

What exactly is it that you want to achieve here? In order to have participation or contribution points related to a custom asset the only thing you need is the config you have. Of course you have to enable the model in control panel. If you would like to have a counter for example to count the number of collections the user has made, you need to create a counter in your config.

The main thing with counters is that they are tied to either a user or the asset in question. This you can control with the <owner-type>. You can put asset, actor or creator in there. If you put asset, you will have a different counter for each collection asset (and in this case it doesn't make sense, since you can create an asset only once emoticon). If it is actor, you will have one for each user who ever added a collection and it will count how many collections he or she adds because it will be incremented on each ADD_COLLECTION action for the user who is adding the collection. If the owner type is creator the counter is incremented for the user who is the owner of the asset, and it doesn't make any sense for add actions either.

Hope this helps,
Zsolt
One more thing. The name of the counter doesn't matter. I named them user.*, or asset.* so that it is evident what type of counter it is just by looking at its name.

And the last thing. If you want it to appear on User Statistics, you explicitly have to add it in the configuration of User Statistics.
Hi Zsolt,

thanks a lot! I write my steps here in case someone else is interested. However, it is still not working. Is it maybe because the collections have been already added and the changes apply only for new collections? I have added add_collection as a social activity. I don't know whether the changes in the counter are retroactive or not.
And another question: how can I set the frequency of equity (counter) updates? The User Statistics portlet is not being updated very often. In Liferay 6.0, we could set the parameter social.equity.equity.log.check.interval in portal-ext. I cannot find any similar one in 6.1.
And another question if you don't mind me shooting one question after another! ;), where are the counters being saved? I checked socialactivitycounter but the currentValue does not represent the value I set for the participation points. Is this the only table that is responsible for saving points?
Thanks for your help! emoticon

And here are the steps I have taken so that add collection and commeting under a collection would be rewarded (still doesn't work, I don't know if it is cache or I have missed anything):
in liferay-social.xml
<liferay-social>
<activity>
<model-name>org.fortiss.fb3.inn­ovationRepository.model.Collection</model-name>
<activity-type>${org.fortiss.f­b3.innovationRepository.social.CollectionActivityKeys.ADD_COLLECTION}</activity-­type>
<language-key>ADD_COLLECTION</language-key>
<log-activity>true</log-ac­tivity>
<contribution-value>0</contribution-value>
<contribution-limit enabled="false" />
<participation-value>10</participation-value>
<participation-limit enabled="false"/>
<counter>
<name>creator.collections</name>
<owner-type>creator</owner-type>
</counter>
<counter>
<name>user.collections</name>
<owner-type>actor</owner-type>
</counter>
</activity>
<activity>
<model-name>org.fortiss.fb3.innovationRepository.model.Collection</model-name>
<activity-type>${com.liferay.portlet.social.model.SocialActivityConstants.TYPE_ADD_COMMENT}</activity-type>
<language-key>ADD_COMMENT</language-key>
<log-activity>true</log-activity>
<contribution-value>0</contribution-value>
<contribution-limit enabled="false" />
<participation-value>3</participation-value>
<participation-limit enabled="false"/>
<counter>
<name>asset.comments</name>
<owner-type>asset</owner-type>
</counter>
<counter>
<name>creator.comments</name>
<owner-type>creator</owner-type>
</counter>
<counter>
<name>user.comments</name>
<owner-type>actor</owner-type>
</counter>
</activity>
In addCollection of CollectionLocalServiceImpl, I had of course added the pertinent resource, asset and then
socialActivityLocalService.addActivity(
collection.getUserId(), collection.getGroupId(), Idea.class.getName(),
collection.getPrimaryKey(), CollectionActivityKeys.ADD_COLLECTION, StringPool.BLANK, 0);

Then I activate the social equity for the model (collection) in control panel.
Then I went to the configuration of User Statistics portlet and added social.counter.user.collections and social.counter.creator.collections to the list of counters.
The values that user statistics shows are still 0 and not all the users that have been adding collections or commments are being shown.
Ok, first of all, User Statistics is update on every page refresh, so unless you're doing something with Ajax without refreshing other portlets, it should update immediately.

Secondly, yes, counters are not retroactively applied, so you should only see it increment for new additions.

As to your third question, yes, you should see every counter in the SocialActivityCounter table.

As for what you are doing, I think there is an error there. You're passing in the class name of the Idea class, while your asset is the Collection class. You have to pass in the asset's class name or at least the one you have your actions configured for (which is in this case 'org.fortiss.fb3.inn­ovate­ionRepository.model.Collection'). Because of this, the system cannot find an activity for this action, it doesn't do anything.
oh sorry, idea was the old name, I have Collection.class.getName() in the new code, so this one is actually correct.
I checked it again and the User Statistics have started counting! This is great! emoticon The only problem now is the old collections.
Can you give me any hints what I should do so that the users that already have added a collection would be given the points? I can add rows manually to database if necessary. And their "adding" is already saved as a social activity in socialactivity portlet. Only the points are not being counted for some reason.
Well if you are sure that they don't have a row (and never had) in the database for this counter, you can use the addActivityCounter(long groupId, long classNameId, long classPK, String name, int ownerType, int currentValue, int totalValue, int startPeriod, int endPeriod) method in SocialActivityLocalService. Maybe an even better option is to select all those social activities and call the addActivity(SocialActivity activity) method for each. This is basically what is normally happening. This would create and increment the necessary counters, even participation. Of course it would do all of these for the current period only, so you cannot create "past" data with it.
Thanks! Strangely, there ARE rows in socialActivity table for these past "adding" actions, they are just being ignored by the User Statistic portlet. I don't know why. I tried to change the date, but it didn't help. I don't see any difference in the rows of socialActivity table for new activities (that are being counted) and past activities. If you say no other table or factors are involved, then it should be some sort of cache problem I guess.
User Statistics shows the current value (which is for the current period) and the total value that should be the total of all current values that exist for that counter.
Hi Zsolt,
i don't need to use "periods" of time to show points
how can i get all the points for each user in all their timelife?
Hi Cesar,

There is a total for each counter that can be retrieved from the counter by calling the getTotalValue() method.

Best,
Zsolt.
Thanks for the great post.
I am not sure how to add my own definitions to liferay-social.xml. Is it necessary to do this with a ext-plugin?
Hi Zsolt.
As far as I've seen, there is no negative impact in Social Equity if a contribution of a user is deleted. For instance, let's imagine a user that posts an inappropiate comment in a message board. If someone (a moderator) deletes the post there is no negative impact in Social Equity, is it? I mean, there is no substraction of his score in Social Equity.
I have another doubt. Imagine a message board with a kaleo workflow for moderation purposes. If a user posts an entry, when is the social equity score added? After or before the post is approved by a moderator?
Thanks. Regards.
Hi Juanjo,

When you delete an asset from the system, the author of the asset loses the contribution points related to that asset, so yes there is some kind of a negative impact. This is however only relates to contribution score that is a reflection of how others rate your content by reading it, subscribing to it, etc. If a user simply posts a message he doesn't get any contribution points for just writing the post, so deleting it wouldn't affect his score. Also note, that deleting an asset doesn't affect participation score in any way.

As for your second question, the points are recorded when the post gets approved.

I hope I could help.

Best,
Zsolt
Hi Zsolt,

Who gets the contribution points when user subscribes to the Blogs portlet (not to the individual blog comments)? I am using Liferay 6.1 GA3 CE and it seems that contribution points are given to any random site member. I have also written little more little in the below thread, please let me know if this is a bug.
https://www.liferay.com/community/forums/-/message_boards/message/34247784