RatingService GET node ratings statistics via REST.

Added node rating stats to the ratings.get webscript (for each scheme):
    average (mean) of all ratings for this node.
    total (sum) of all ratings for this node.
    count of all ratings for this node.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21108 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Neil McErlean
2010-07-12 16:07:08 +00:00
parent f156a4f4b5
commit e80119fe6c
4 changed files with 148 additions and 46 deletions

View File

@@ -1,11 +1,41 @@
<webscript>
<shortname>GET rating</shortname>
<description><![CDATA[
Gets the list of ratings for the specified NodeRef if there are any.<br/>
The ratings returned will be those applied by the currently authenticated user. There
will be one for each rating scheme in which the user has submitted a rating. If the
currently authenticated user has not applied any ratings to this content the list
will be empty.
Gets the list of ratings for the specified NodeRef (if there are any) as well as some
general statistics on ratings for the specified node.<br/>
The ratings returned will only include those applied by the currently authenticated user. There
will be one for each rating scheme in which the user has submitted a rating.<br/>
The returned data will be of the form:<br/>
{<br/>
&nbsp;&nbsp;"nodeRef": "workspace:\/\/SpacesStore\/d0b163fe-050d-43f5-88e4-db1794a3e5cd",<br/>
&nbsp;&nbsp;"ratings":<br/>
&nbsp;&nbsp;[<br/>
&nbsp;&nbsp;&nbsp;&nbsp;{<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"ratingScheme": "fiveStarRatingScheme",<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"rating": 5,<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"appliedAt": "12 Jul 2010 16:38:05 GMT+0100 (BST)",<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"appliedBy": "UserOne"<br/>
&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
&nbsp;&nbsp;],<br/>
&nbsp;&nbsp;"nodeStatistics":<br/>
&nbsp;&nbsp;{<br/>
&nbsp;&nbsp;&nbsp;&nbsp;"likesRatingScheme":<br/>
&nbsp;&nbsp;&nbsp;&nbsp;{<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"averageRating": 3,<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"ratingsTotal": 3,<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"ratingsCount": 1<br/>
&nbsp;&nbsp;&nbsp;&nbsp;}<br/>
&nbsp;&nbsp;}<br/>
}<br/>
with the following meanings:<br/>
nodeRef: the nodeRef whose ratings are requested.<br/>
ratings/ratingScheme: the rating scheme name<br/>
ratings/rating: the rating applied to the named noderef in the above scheme by the current user<br/>
ratings/appliedAt: the datetime when the above rating was applied<br/>
ratings/appliedBy: the user who applied the above rating (the current user)<br/>
nodeStatistics/averageRating: the average (mean) rating on this node in the named rating scheme for all users<br/>
nodeStatistics/ratingsTotal: the total score (sum) of all ratings on this node in the named rating scheme<br/>
nodeStatistics/ratingsCount: the total number of applied ratings on this node in the named rating scheme.<br/>
]]>
</description>
<url>/api/node/{store_type}/{store_id}/{id}/ratings</url>

View File

@@ -14,7 +14,18 @@
"appliedBy": "${rating.appliedBy!""}"
}<#if rating_has_next>,</#if>
</#list>
]
],
"nodeStatistics":
{
<#list averageRatings?keys as schemeName>
"${schemeName!""}":
{
"averageRating": ${averageRatings[schemeName]?c},
"ratingsTotal": ${ratingsTotals[schemeName]?c},
"ratingsCount": ${ratingsCounts[schemeName]?c}
}<#if schemeName_has_next>,</#if>
</#list>
}
}
}
</#escape>

View File

@@ -47,9 +47,25 @@ import org.springframework.extensions.webscripts.TestWebScriptServer.Response;
*/
public class RatingRestApiTest extends BaseWebScriptTest
{
// Miscellaneous constants used throughout this test class.
private static final String FIVE_STAR_RATING_SCHEME = "fiveStarRatingScheme";
private static final String LIKES_RATING_SCHEME = "likesRatingScheme";
private static final String USER_ONE = "UserOne";
private static final String USER_TWO = "UserTwo";
private static final String RATING_SCHEMES = "ratingSchemes";
private static final String NAME = "name";
private static final String MIN_RATING = "minRating";
private static final String MAX_RATING = "maxRating";
private static final String RATINGS = "ratings";
private static final String NODE_REF = "nodeRef";
private static final String DATA = "data";
private static final String RATINGS_TOTAL = "ratingsTotal";
private static final String RATINGS_COUNT = "ratingsCount";
private static final String AVERAGE_RATING = "averageRating";
private static final String NODE_STATISTICS = "nodeStatistics";
private final static String NODE_RATINGS_URL_FORMAT = "/api/node/{0}/ratings";
private final static String GET_RATING_DEFS_URL = "/api/rating/schemedefinitions";
@@ -122,22 +138,22 @@ public class RatingRestApiTest extends BaseWebScriptTest
JSONObject jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
JSONObject dataObj = (JSONObject)jsonRsp.get("data");
JSONObject dataObj = (JSONObject)jsonRsp.get(DATA);
assertNotNull("JSON 'data' object was null", dataObj);
JSONArray ratingSchemesArray = (JSONArray)dataObj.get("ratingSchemes");
JSONArray ratingSchemesArray = (JSONArray)dataObj.get(RATING_SCHEMES);
assertNotNull("JSON 'ratingSchemesArray' object was null", ratingSchemesArray);
assertEquals(2, ratingSchemesArray.length());
JSONObject scheme1 = ratingSchemesArray.getJSONObject(0);
JSONObject scheme2 = ratingSchemesArray.getJSONObject(1);
assertEquals("likesRatingScheme", scheme1.getString("name"));
assertEquals(1, scheme1.getInt("minRating"));
assertEquals(1, scheme1.getInt("maxRating"));
assertEquals("fiveStarRatingScheme", scheme2.getString("name"));
assertEquals(1, scheme2.getInt("minRating"));
assertEquals(5, scheme2.getInt("maxRating"));
assertEquals(LIKES_RATING_SCHEME, scheme1.getString(NAME));
assertEquals(1, scheme1.getInt(MIN_RATING));
assertEquals(1, scheme1.getInt(MAX_RATING));
assertEquals(FIVE_STAR_RATING_SCHEME, scheme2.getString(NAME));
assertEquals(1, scheme2.getInt(MIN_RATING));
assertEquals(5, scheme2.getInt(MAX_RATING));
}
public void testGetRatingsFromUnratedNodeRef() throws Exception
@@ -150,29 +166,41 @@ public class RatingRestApiTest extends BaseWebScriptTest
JSONObject jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
JSONObject dataObj = (JSONObject)jsonRsp.get("data");
JSONObject dataObj = (JSONObject)jsonRsp.get(DATA);
assertNotNull("JSON 'data' object was null", dataObj);
assertEquals(testNode.toString(), dataObj.getString("nodeRef"));
final JSONArray ratingsArray = dataObj.getJSONArray("ratings");
assertEquals(testNode.toString(), dataObj.getString(NODE_REF));
final JSONArray ratingsArray = dataObj.getJSONArray(RATINGS);
assertEquals(0, ratingsArray.length());
// Unrated content
JSONObject statsObject = dataObj.getJSONObject(NODE_STATISTICS);
JSONObject likesStats = statsObject.getJSONObject(LIKES_RATING_SCHEME);
assertEquals("Average rating was wrong.", -1.0, likesStats.getDouble(AVERAGE_RATING));
assertEquals("Ratings count rating was wrong.", 0, likesStats.getInt(RATINGS_COUNT));
assertEquals("Ratings total was wrong.", 0, likesStats.getInt(RATINGS_TOTAL));
}
public void testApplyRatingAndRetrieve() throws Exception
/**
* This test method applies ratings from multiple users in a single rating
* scheme to a single test node. It then retrieves those ratings to ensure they
* were persisted correctly.
*/
public void testApplyRatingsAsMultipleUsersAndRetrieve() throws Exception
{
// POST a new rating to the testNode - as User One.
AuthenticationUtil.setFullyAuthenticatedUser(USER_ONE);
final String ratingUrl = getRatingUrl(testNode);
final String testNodeRatingUrl = getRatingUrl(testNode);
final int ratingValue = 5;
final int userOneRatingValue = 5;
String jsonString = new JSONStringer().object()
.key("rating").value(ratingValue)
.key("ratingScheme").value("fiveStarRatingScheme")
.key("rating").value(userOneRatingValue)
.key("ratingScheme").value(FIVE_STAR_RATING_SCHEME)
.endObject()
.toString();
Response rsp = sendRequest(new PostRequest(ratingUrl,
Response rsp = sendRequest(new PostRequest(testNodeRatingUrl,
jsonString, APPLICATION_JSON), 200);
String rspContent = rsp.getContentAsString();
@@ -180,28 +208,34 @@ public class RatingRestApiTest extends BaseWebScriptTest
// Get the returned URL and validate
JSONObject jsonRsp = new JSONObject(new JSONTokener(rspContent));
JSONObject dataObj = (JSONObject)jsonRsp.get("data");
JSONObject dataObj = (JSONObject)jsonRsp.get(DATA);
assertNotNull("JSON 'data' object was null", dataObj);
String returnedUrl = dataObj.getString("ratedNodeUrl");
assertEquals(ratingUrl, returnedUrl);
assertEquals("fiveStarRatingScheme", dataObj.getString("ratingScheme"));
assertEquals(ratingValue, dataObj.getInt("rating"));
assertEquals(testNodeRatingUrl, returnedUrl);
assertEquals(FIVE_STAR_RATING_SCHEME, dataObj.getString("ratingScheme"));
assertEquals(userOneRatingValue, dataObj.getInt("rating"));
// Now GET the ratings via that returned URL
rsp = sendRequest(new GetRequest(ratingUrl), 200);
rsp = sendRequest(new GetRequest(testNodeRatingUrl), 200);
jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
dataObj = (JSONObject)jsonRsp.get("data");
dataObj = (JSONObject)jsonRsp.get(DATA);
assertNotNull("JSON 'data' object was null", dataObj);
// There should only be the one rating in there.
final JSONArray ratingsArray = dataObj.getJSONArray("ratings");
final JSONArray ratingsArray = dataObj.getJSONArray(RATINGS);
assertEquals(1, ratingsArray.length());
JSONObject firstRating = (JSONObject)ratingsArray.get(0);
assertEquals(ratingValue, firstRating.getInt("rating"));
assertEquals("fiveStarRatingScheme", firstRating.getString("ratingScheme"));
JSONObject recoveredRating = (JSONObject)ratingsArray.get(0);
assertEquals(userOneRatingValue, recoveredRating.getInt("rating"));
assertEquals(FIVE_STAR_RATING_SCHEME, recoveredRating.getString("ratingScheme"));
// As well as the average, total ratings.
JSONObject statsObject = dataObj.getJSONObject(NODE_STATISTICS);
JSONObject fiveStarStats = statsObject.getJSONObject(FIVE_STAR_RATING_SCHEME);
assertEquals("Average rating was wrong.", (double)userOneRatingValue, fiveStarStats.getDouble(AVERAGE_RATING));
assertEquals("Ratings count rating was wrong.", 1, fiveStarStats.getInt(RATINGS_COUNT));
assertEquals("Ratings total was wrong.", userOneRatingValue, fiveStarStats.getInt(RATINGS_TOTAL));
// Now POST a second new rating to the testNode - as User Two.
@@ -210,18 +244,18 @@ public class RatingRestApiTest extends BaseWebScriptTest
final int userTwoRatingValue = 3;
jsonString = new JSONStringer().object()
.key("rating").value(userTwoRatingValue)
.key("ratingScheme").value("fiveStarRatingScheme")
.key("ratingScheme").value(FIVE_STAR_RATING_SCHEME)
.endObject()
.toString();
rsp = sendRequest(new PostRequest(ratingUrl,
rsp = sendRequest(new PostRequest(testNodeRatingUrl,
jsonString, APPLICATION_JSON), 200);
rspContent = rsp.getContentAsString();
// Get the returned URL and validate
jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
dataObj = (JSONObject)jsonRsp.get("data");
dataObj = (JSONObject)jsonRsp.get(DATA);
assertNotNull("JSON 'data' object was null", dataObj);
returnedUrl = dataObj.getString("ratedNodeUrl");
@@ -230,18 +264,25 @@ public class RatingRestApiTest extends BaseWebScriptTest
jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
dataObj = (JSONObject)jsonRsp.get("data");
dataObj = (JSONObject)jsonRsp.get(DATA);
assertNotNull("JSON 'data' object was null", dataObj);
// There should still only be the one rating in the results - because we're running
// as UserTwo and should not see UserOne's rating.
final JSONArray userTwoRatingsArray = dataObj.getJSONArray("ratings");
final JSONArray userTwoRatingsArray = dataObj.getJSONArray(RATINGS);
assertEquals(1, userTwoRatingsArray.length());
JSONObject secondRating = (JSONObject)userTwoRatingsArray.get(0);
assertEquals(userTwoRatingValue, secondRating.getInt("rating"));
assertEquals("fiveStarRatingScheme", secondRating.getString("ratingScheme"));
assertEquals(FIVE_STAR_RATING_SCHEME, secondRating.getString("ratingScheme"));
//TODO Could probably put the GET average call here then.
// Now the average should have changed.
statsObject = dataObj.getJSONObject(NODE_STATISTICS);
fiveStarStats = statsObject.getJSONObject(FIVE_STAR_RATING_SCHEME);
assertEquals("Average rating was wrong.", (userOneRatingValue + userTwoRatingValue) / 2.0,
fiveStarStats.getDouble(AVERAGE_RATING));
assertEquals("Ratings count rating was wrong.", 2, fiveStarStats.getInt(RATINGS_COUNT));
assertEquals("Ratings total was wrong.", userOneRatingValue + userTwoRatingValue,
fiveStarStats.getInt(RATINGS_TOTAL));
}
/**

View File

@@ -37,6 +37,13 @@ import org.springframework.extensions.webscripts.WebScriptRequest;
*/
public class RatingsGet extends AbstractRatingWebScript
{
private static final String NODE_REF = "nodeRef";
private static final String RATINGS = "ratings";
private static final String AVERAGE_RATINGS = "averageRatings";
private static final String RATINGS_TOTALS = "ratingsTotals";
private static final String RATINGS_COUNTS = "ratingsCounts";
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
@@ -44,19 +51,32 @@ public class RatingsGet extends AbstractRatingWebScript
NodeRef nodeRef = parseRequestForNodeRef(req);
List<Rating> ratings = new ArrayList<Rating>();
// These are the data for the current user's ratings of this node, if any.
List<Rating> myRatings = new ArrayList<Rating>();
// These maps hold the average rating, accumulated total of all ratings and
// the number of ratings applied for this node as a function of rating scheme.
Map<String, Float> averageRatings = new HashMap<String, Float>();
Map<String, Integer> ratingsTotals = new HashMap<String, Integer>();
Map<String, Integer> ratingsCounts = new HashMap<String, Integer>();
for (String schemeName : ratingService.getRatingSchemes().keySet())
{
final Rating ratingByCurrentUser = ratingService.getRatingByCurrentUser(nodeRef, schemeName);
if (ratingByCurrentUser != null)
{
ratings.add(ratingByCurrentUser);
myRatings.add(ratingByCurrentUser);
}
averageRatings.put(schemeName, ratingService.getAverageRating(nodeRef, schemeName));
ratingsTotals.put(schemeName, ratingService.getTotalRating(nodeRef, schemeName));
ratingsCounts.put(schemeName, ratingService.getRatingsCount(nodeRef, schemeName));
}
model.put("nodeRef", nodeRef.toString());
model.put("ratings", ratings);
model.put(NODE_REF, nodeRef.toString());
model.put(RATINGS, myRatings);
model.put(AVERAGE_RATINGS, averageRatings);
model.put(RATINGS_TOTALS, ratingsTotals);
model.put(RATINGS_COUNTS, ratingsCounts);
return model;
}