diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rating/rating.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/rating/rating.post.desc.xml
new file mode 100644
index 0000000000..eaa82959ba
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rating/rating.post.desc.xml
@@ -0,0 +1,22 @@
+
+ POST a rating to a NodeRef
+
+ The rating consists of a score and a rating scheme name. The rating scheme will
+ define a minimum and a maximum allowed score and it is the responsibility of the
+ caller of this webscript to ensure that the scheme name is valid and that the posted
+ score is within the allowed range.
+ The rating will be applied using the fully authenticated user who makes the POST call.
+ The body of the post should be in the form, e.g.
+ {
+ "rating": 5,
+ "ratingScheme": "fiveStarRatingScheme"
+ }
+ ]]>
+
+ /api/node/{store_type}/{store_id}/{id}/ratings
+
+ user
+ required
+ internal
+
\ No newline at end of file
diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/rating/rating.post.json.ftl b/config/alfresco/templates/webscripts/org/alfresco/repository/rating/rating.post.json.ftl
new file mode 100644
index 0000000000..0e26e23ff6
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/rating/rating.post.json.ftl
@@ -0,0 +1,8 @@
+<#escape x as jsonUtils.encodeJSONString(x)>
+{
+ "data":
+ {
+ "ratedNodeUrl": "${ratedNode!""}"
+ }
+}
+#escape>
\ No newline at end of file
diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml
index b65f9590aa..f524c1ea73 100644
--- a/config/alfresco/web-scripts-application-context.xml
+++ b/config/alfresco/web-scripts-application-context.xml
@@ -753,6 +753,11 @@
parent="abstractRatingWebScript">
+
+
+
diff --git a/source/java/org/alfresco/repo/web/scripts/rating/RatingPost.java b/source/java/org/alfresco/repo/web/scripts/rating/RatingPost.java
index b0b0fdfde2..8b90d6fb20 100644
--- a/source/java/org/alfresco/repo/web/scripts/rating/RatingPost.java
+++ b/source/java/org/alfresco/repo/web/scripts/rating/RatingPost.java
@@ -18,21 +18,88 @@
*/
package org.alfresco.repo.web.scripts.rating;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.HashMap;
import java.util.Map;
+import org.alfresco.service.cmr.rating.RatingScheme;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
+import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
- * @author unknown
- *
+ * This class is the controller for the rating.post webscript.
+ *
+ * @author Neil McErlean
+ * @since 3.4
*/
public class RatingPost extends AbstractRatingWebScript
{
+ // Web script parameters.
+ private static final String RATING_SCHEME = "ratingScheme";
+ private static final String RATING = "rating";
+ private static final String RATED_NODE = "ratedNode";
+
+ // Url format
+ private final static String NODE_RATINGS_URL_FORMAT = "/api/node/{0}/ratings";
+
@Override
protected Map executeImpl(WebScriptRequest req, Status status, Cache cache)
{
- return null;
+ Map model = new HashMap();
+
+ NodeRef nodeRefToBeRated = parseRequestForNodeRef(req);
+
+ JSONObject json = null;
+ try
+ {
+ // read request json
+ json = new JSONObject(new JSONTokener(req.getContent().getContent()));
+
+ // Check mandatory parameters.
+ if (json.has(RATING) == false)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "rating parameter missing when applying rating");
+ }
+ if (json.has(RATING_SCHEME) == false)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "schemeName parameter missing when applying rating");
+ }
+
+ // Check that the scheme name actually exists
+ String schemeName = json.getString(RATING_SCHEME);
+ RatingScheme scheme = ratingService.getRatingScheme(schemeName);
+ if (scheme == null)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Unknown scheme name: " + schemeName);
+ }
+
+ // Range checking of the rating score will be done within the RatingService.
+ // So we can just apply the rating.
+ int rating = json.getInt(RATING);
+ ratingService.applyRating(nodeRefToBeRated, rating, schemeName);
+
+ // We'll return the URL to the ratings of the just-rated node.
+ String ratedNodeUrlFragment = nodeRefToBeRated.toString().replace("://", "/");
+ String ratedNodeUrl = MessageFormat.format(NODE_RATINGS_URL_FORMAT, ratedNodeUrlFragment);
+
+ model.put(RATED_NODE, ratedNodeUrl);
+ }
+ catch (IOException iox)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not read content from req.", iox);
+ }
+ catch (JSONException je)
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Could not parse JSON from req.", je);
+ }
+
+ return model;
}
}
diff --git a/source/java/org/alfresco/repo/web/scripts/rating/RatingPut.java b/source/java/org/alfresco/repo/web/scripts/rating/RatingPut.java
deleted file mode 100644
index 996e263a5a..0000000000
--- a/source/java/org/alfresco/repo/web/scripts/rating/RatingPut.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2005-2010 Alfresco Software Limited.
- *
- * This file is part of Alfresco
- *
- * Alfresco is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Alfresco is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Alfresco. If not, see .
- */
-package org.alfresco.repo.web.scripts.rating;
-
-import java.util.Map;
-
-import org.springframework.extensions.webscripts.Cache;
-import org.springframework.extensions.webscripts.Status;
-import org.springframework.extensions.webscripts.WebScriptRequest;
-
-/**
- * @author unknown
- *
- */
-public class RatingPut extends RatingPost
-{
- @Override
- protected Map executeImpl(WebScriptRequest req, Status status, Cache cache)
- {
- return null;
- }
-}
diff --git a/source/java/org/alfresco/repo/web/scripts/rating/RatingRestApiTest.java b/source/java/org/alfresco/repo/web/scripts/rating/RatingRestApiTest.java
index b2f017a319..80efb4cd3f 100644
--- a/source/java/org/alfresco/repo/web/scripts/rating/RatingRestApiTest.java
+++ b/source/java/org/alfresco/repo/web/scripts/rating/RatingRestApiTest.java
@@ -28,40 +28,57 @@ import org.alfresco.repo.web.scripts.BaseWebScriptTest;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.security.MutableAuthenticationService;
+import org.alfresco.service.cmr.security.PersonService;
+import org.alfresco.util.PropertyMap;
import org.json.JSONArray;
import org.json.JSONObject;
+import org.json.JSONStringer;
import org.json.JSONTokener;
import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest;
+import org.springframework.extensions.webscripts.TestWebScriptServer.PostRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.Response;
public class RatingRestApiTest extends BaseWebScriptTest
{
- private final static String GET_RATINGS_URL_FORMAT = "/api/node/{0}/ratings";
+ private static final String USER_ONE = "UserOne";
+ private static final String USER_TWO = "UserTwo";
+
+ private final static String NODE_RATINGS_URL_FORMAT = "/api/node/{0}/ratings";
private final static String GET_RATING_DEFS_URL = "/api/rating/schemedefinitions";
private static final String APPLICATION_JSON = "application/json";
private NodeRef testNode;
- protected NodeService nodeService;
- protected Repository repositoryHelper;
- protected RetryingTransactionHelper transactionHelper;
+ private MutableAuthenticationService authenticationService;
+ private NodeService nodeService;
+ private PersonService personService;
+ private Repository repositoryHelper;
+ private RetryingTransactionHelper transactionHelper;
@Override
protected void setUp() throws Exception
{
super.setUp();
+ authenticationService = (MutableAuthenticationService) getServer().getApplicationContext().getBean("AuthenticationService");
nodeService = (NodeService) getServer().getApplicationContext().getBean("NodeService");
+ personService = (PersonService) getServer().getApplicationContext().getBean("PersonService");
repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper");
transactionHelper = (RetryingTransactionHelper)getServer().getApplicationContext().getBean("retryingTransactionHelper");
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
- // Create a test node which we will rate. It doesn't matter that it has no content.
+ // Create some users to rate each other's content
+ // and a test node which we will rate.
+ // It doesn't matter that it has no content.
testNode = transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback()
{
public NodeRef execute() throws Throwable
{
+ createUser(USER_ONE);
+ createUser(USER_TWO);
+
ChildAssociationRef result = nodeService.createNode(repositoryHelper.getCompanyHome(),
ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS,
ContentModel.TYPE_CONTENT, null);
@@ -74,6 +91,9 @@ public class RatingRestApiTest extends BaseWebScriptTest
public void tearDown() throws Exception
{
super.tearDown();
+
+ AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
+
transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback()
{
public Void execute() throws Throwable
@@ -81,6 +101,8 @@ public class RatingRestApiTest extends BaseWebScriptTest
if (testNode != null && nodeService.exists(testNode))
{
nodeService.deleteNode(testNode);
+ deleteUser(USER_ONE);
+ deleteUser(USER_TWO);
}
return null;
}
@@ -88,9 +110,7 @@ public class RatingRestApiTest extends BaseWebScriptTest
}
//TODO test POST out-of-range.
- //TODO test get my-ratings on node with mine & others' ratings.
//TODO test GET average
- //TODO test POST and PUT (same)
public void testGetRatingSchemeDefinitions() throws Exception
{
@@ -100,9 +120,6 @@ public class RatingRestApiTest extends BaseWebScriptTest
JSONObject jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
-
- System.err.println(jsonRsp);
-
JSONObject dataObj = (JSONObject)jsonRsp.get("data");
assertNotNull("JSON 'data' object was null", dataObj);
@@ -124,16 +141,13 @@ public class RatingRestApiTest extends BaseWebScriptTest
public void testGetRatingsFromUnratedNodeRef() throws Exception
{
// GET ratings
- String nodeUrl = testNode.toString().replace("://", "/");
- String ratingUrl = MessageFormat.format(GET_RATINGS_URL_FORMAT, nodeUrl);
+ String ratingUrl = getRatingUrl(testNode);
final int expectedStatus = 200;
Response rsp = sendRequest(new GetRequest(ratingUrl), expectedStatus);
JSONObject jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
- System.err.println(jsonRsp);
-
JSONObject dataObj = (JSONObject)jsonRsp.get("data");
assertNotNull("JSON 'data' object was null", dataObj);
@@ -141,4 +155,126 @@ public class RatingRestApiTest extends BaseWebScriptTest
final JSONArray ratingsArray = dataObj.getJSONArray("ratings");
assertEquals(0, ratingsArray.length());
}
+
+ public void testApplyRatingAndRetrieve() throws Exception
+ {
+ // POST a new rating to the testNode - as User One.
+ AuthenticationUtil.setFullyAuthenticatedUser(USER_ONE);
+
+ final String ratingUrl = getRatingUrl(testNode);
+
+ final int ratingValue = 5;
+ String jsonString = new JSONStringer().object()
+ .key("rating").value(ratingValue)
+ .key("ratingScheme").value("fiveStarRatingScheme")
+ .endObject()
+ .toString();
+
+ Response rsp = sendRequest(new PostRequest(ratingUrl,
+ jsonString, APPLICATION_JSON), 200);
+
+ String rspContent = rsp.getContentAsString();
+
+ // Get the returned URL and validate
+ JSONObject jsonRsp = new JSONObject(new JSONTokener(rspContent));
+
+ JSONObject dataObj = (JSONObject)jsonRsp.get("data");
+ assertNotNull("JSON 'data' object was null", dataObj);
+ String returnedUrl = dataObj.getString("ratedNodeUrl");
+ assertEquals(ratingUrl, returnedUrl);
+
+ // Now GET the ratings via that returned URL
+ rsp = sendRequest(new GetRequest(ratingUrl), 200);
+
+ jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
+
+ 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");
+ assertEquals(1, ratingsArray.length());
+ JSONObject firstRating = (JSONObject)ratingsArray.get(0);
+ assertEquals(ratingValue, firstRating.getInt("rating"));
+ assertEquals("fiveStarRatingScheme", firstRating.getString("ratingScheme"));
+
+
+
+ // Now POST a second new rating to the testNode - as User Two.
+ AuthenticationUtil.setFullyAuthenticatedUser(USER_TWO);
+
+ final int userTwoRatingValue = 3;
+ jsonString = new JSONStringer().object()
+ .key("rating").value(userTwoRatingValue)
+ .key("ratingScheme").value("fiveStarRatingScheme")
+ .endObject()
+ .toString();
+
+ rsp = sendRequest(new PostRequest(ratingUrl,
+ 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");
+ assertNotNull("JSON 'data' object was null", dataObj);
+ returnedUrl = dataObj.getString("ratedNodeUrl");
+
+ // Again GET the ratings via that returned URL
+ rsp = sendRequest(new GetRequest(returnedUrl), 200);
+
+ jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
+
+ 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");
+ assertEquals(1, userTwoRatingsArray.length());
+ JSONObject secondRating = (JSONObject)userTwoRatingsArray.get(0);
+ assertEquals(userTwoRatingValue, secondRating.getInt("rating"));
+ assertEquals("fiveStarRatingScheme", secondRating.getString("ratingScheme"));
+
+ //TODO Could probably put the GET average call here then.
+ }
+
+ /**
+ * This method gives the 'ratings' URL for the specified NodeRef.
+ */
+ private String getRatingUrl(NodeRef nodeRef)
+ {
+ String nodeUrl = nodeRef.toString().replace("://", "/");
+ String ratingUrl = MessageFormat.format(NODE_RATINGS_URL_FORMAT, nodeUrl);
+ return ratingUrl;
+ }
+
+ private void createUser(String userName)
+ {
+ if (! authenticationService.authenticationExists(userName))
+ {
+ authenticationService.createAuthentication(userName, "PWD".toCharArray());
+ }
+
+ if (! personService.personExists(userName))
+ {
+ PropertyMap ppOne = new PropertyMap(4);
+ ppOne.put(ContentModel.PROP_USERNAME, userName);
+ ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
+ ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
+ ppOne.put(ContentModel.PROP_EMAIL, "email@email.com");
+ ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");
+
+ personService.createPerson(ppOne);
+ }
+ }
+
+ private void deleteUser(String userName)
+ {
+ if (personService.personExists(userName))
+ {
+ personService.deletePerson(userName);
+ }
+ }
}