Merged BRANCHES/DEV/SWIFT to HEAD:

28466: Fix for ALF-6541. maintainAspectRatio does not default to true as documented.
        Fixed the javadoc to reflect reality.

Merged BRANCHES/DEV/SWIFT to HEAD:
   28482 Implementation of ALF-8969 Lucene removal: Blog webscripts.
        ** Checking this in on Swift branch, as I have the work there. Will merge to HEAD.

        The blog webscript controllers have been ported from JavaScript to Java.
        A new foundation service, the BlogService has been added and the impls of the webscript controllers delegate into that service, thus encapsulating business logic within the service.
        The API for this service is based on the requirements of the existing webscripts, but is for the most part a 'sensible' API. One controller (blogposts.get.js) had very domain-specific requirements (get all of my drafts and all published posts) and it is implemented as a deprecated public method on the service.
        The API is not complete, but represents a good starting point for any future feature development.
        The various Lucene queries have been replaced with calls to the nodeservice (as an impl detail within the BlogService) which get all blog post nodes and then post-filter them based on property values, aspect/property presence etc. This will       be refactored into a CannedQuery in a subsequent check-in.
 
        I've written new test cases aimed at this API & have extended the REST API tests.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28483 Prevent NPEs in some circumstances. Related to ALF-8969.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28484 Fixing activity reports for Blog posting. Following on from previous chagnes related to ALF-8969.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28597 ALF-8969. Introduction of brute force Canned Queries for BlogService query methods.
        This will be merged to HEAD after a chat with Jan/Derek.

        Introduced 'brute force' Canned Queries for the various BlogService query methods.
          These use the underlying nodeService to retrieve result sets.
          They must use the small-n nodeService in order to get full result sets.
          Therefore I have had to add some AFTER_ACL_ENTRY checks to the BlogService_security bean for the query methods.
        Added various CannedQuery classes for the BlogService queries. They currently split into two:
          1. a GetBlogPostsCannedQuery which goes some way towards providing configurable query support, albeit driven by the needs of the Blog Service REST API.
          2. a DraftsAndPublishedBlogPostsCannedQuery, which is a very specific CQ aimed at a very specific scenario in the REST API.
        Changed the BlogService API to return a BlogPostInfo (simple POJO) rather than the less extensible NodeRef.
          This affected the webscript implementations.
        Added BlogPostInfo as an acceptable return type for security-based filtering in ACLEntryAfterInvocationProvider.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28598 Repackaged the CannedQuery-related classes to a dedicated subpackage. ALF-8969.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28602 Replacement of some JS controllers with Java-based ports. Part of ALF-8969.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28603 Disabling two test cases pending a refactoring. Related to ALF-8969.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28604 Fixing a compilation error.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28606 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Neil McErlean
2011-06-27 10:10:07 +00:00
parent e353ed8f0a
commit 9e38ed78ea
33 changed files with 1965 additions and 665 deletions

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs;
import org.alfresco.repo.blog.BlogService;
import org.alfresco.repo.model.Repository;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.site.SiteService;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
/**
* @author Neil Mc Erlean
* @since 4.0
*/
public abstract class AbstractBlogWebScript extends DeclarativeWebScript
{
// Various common parameter strings in the blog webscripts.
protected static final String CONTAINER = "container";
protected static final String CONTENT = "content";
protected static final String DATA = "data";
protected static final String DRAFT = "draft";
protected static final String EXTERNAL_BLOG_CONFIG = "externalBlogConfig";
protected static final String ITEM = "item";
protected static final String NODE = "node";
protected static final String PAGE = "page";
protected static final String SITE = "site";
protected static final String TAGS = "tags";
protected static final String TITLE = "title";
// Injected services
protected Repository repository;
protected BlogService blogService;
protected NodeService nodeService;
protected SiteService siteService;
//TODO Remove this after full refactor
protected ServiceRegistry services;
public void setServiceRegistry(ServiceRegistry services)
{
this.services = services;
}
public void setRepository(Repository repository)
{
this.repository = repository;
}
public void setBlogService(BlogService blogService)
{
this.blogService = blogService;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setSiteService(SiteService siteService)
{
this.siteService = siteService;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs;
import org.alfresco.repo.blog.BlogService;
import org.alfresco.repo.blog.BlogServiceImplTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
/**
* This class is a holder for the various test classes associated with the {@link BlogService}.
* It is not (at the time of writing) intended to be incorporated into the automatic build
* which will find the various test classes and run them individually.
*
* @author Neil Mc Erlean
* @since 4.0
*/
@RunWith(Suite.class)
@Suite.SuiteClasses({
BlogServiceImplTest.class,
BlogServiceTest.class
})
public class AllBlogTests
{
// Intentionally empty
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.BlogIntegrationModel;
import org.alfresco.service.namespace.QName;
import org.json.JSONException;
import org.json.JSONObject;
/**
* This class is a port of a previous JavaScript library.
*
* @author Neil Mc Erlean (based on previous JavaScript)
* @since 4.0
* @deprecated This class should not be extended or reused as it may be refactored.
*/
public class BlogLibJs
{
/**
* Fetches the blog properties from the json object and adds them to an array
* using the correct property names as indexes.
*/
public static Map<QName, Serializable> getBlogPropertiesArray(JSONObject json)
{
Map<QName, Serializable> arr = new HashMap<QName, Serializable>();
putJSONEntryInMap(json, arr, "blogType", BlogIntegrationModel.PROP_BLOG_IMPLEMENTATION);
putJSONEntryInMap(json, arr, "blogId", BlogIntegrationModel.PROP_ID);
putJSONEntryInMap(json, arr, "blogName", BlogIntegrationModel.PROP_NAME);
putJSONEntryInMap(json, arr, "blogDescription", BlogIntegrationModel.PROP_DESCRIPTION);
putJSONEntryInMap(json, arr, "blogUrl", BlogIntegrationModel.PROP_URL);
putJSONEntryInMap(json, arr, "username", BlogIntegrationModel.PROP_USER_NAME);
putJSONEntryInMap(json, arr, "password", BlogIntegrationModel.PROP_PASSWORD);
return arr;
}
private static void putJSONEntryInMap(JSONObject json,
Map<QName, Serializable> arr, String jsonKey, QName mapKey)
{
try
{
if (json.has(jsonKey))
{
arr.put(mapKey, json.getString(jsonKey));
}
} catch (JSONException ignored)
{
// Intentionally empty
}
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.BlogIntegrationModel;
import org.alfresco.model.ContentModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* This class is a port of a previous JavaScript library.
*
* @author Neil Mc Erlean (based on previous JavaScript)
* @since 4.0
*/
public class BlogPostLibJs
{
//FIXME It will be refactored when the other services are ported from JavaScript to Java.
/**
* Checks whether a blog configuration is available
* This should at some point also check whether the configuration is enabled.
*
* @param node the node that should be checked. Will check all parents if
* the node itself doesn't contain a configuration.
* @return {boolean} whether a configuration could be found.
*/
public static boolean hasExternalBlogConfiguration(NodeRef node, ServiceRegistry services)
{
if (node == null)
{
return false;
}
else if (services.getNodeService().hasAspect(node, BlogIntegrationModel.ASPECT_BLOG_DETAILS))
{
return true;
}
else
{
return hasExternalBlogConfiguration(services.getNodeService().getPrimaryParent(node).getParentRef(), services);
}
}
public static Map<String, Object> getBlogPostData(NodeRef node, ServiceRegistry services)
{
Map<String, Object> data = new HashMap<String, Object>();
data.put("node", node);
String creator = (String)services.getNodeService().getProperty(node, ContentModel.PROP_CREATOR);
data.put("author", services.getPersonService().getPerson(creator));
data.put("commentCount", CommentsLibJs.getCommentsCount(node, services));
// is the post published
Serializable published = services.getNodeService().getProperty(node, ContentModel.PROP_PUBLISHED);
boolean isPublished = published != null;
if (isPublished)
{
data.put("releasedDate", published);
}
// draft
data.put("isDraft", !isPublished);
// set the isUpdated flag
Date updatedDate = (Date) services.getNodeService().getProperty(node, ContentModel.PROP_UPDATED);
boolean isUpdated = updatedDate != null;
data.put("isUpdated", isUpdated);
if (isUpdated)
{
data.put("updatedDate", updatedDate);
}
// fetch standard created/modified dates
data.put("createdDate", services.getNodeService().getProperty(node, ContentModel.PROP_CREATED));
data.put("modifiedDate", services.getNodeService().getProperty(node, ContentModel.PROP_MODIFIED));
// does the external post require an update?
Date lastUpdate = (Date) services.getNodeService().getProperty(node, BlogIntegrationModel.PROP_LAST_UPDATE);
if (isPublished && lastUpdate != null)
{
// we either use the release or updated date
Date modifiedDate = (Date) data.get("releasedDate");
if (isUpdated)
{
modifiedDate = (Date) data.get("updatedDate");
}
data.put("outOfDate", modifiedDate.getTime() - lastUpdate.getTime() > 5000L);
}
else
{
data.put("outOfDate", false);
}
data.put("tags", services.getTaggingService().getTags(node));
return data;
}
}

View File

@@ -0,0 +1,653 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.site.SiteModel;
import org.alfresco.repo.web.scripts.BaseWebScriptTest;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.cmr.site.SiteVisibility;
import org.alfresco.util.PropertyMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONStringer;
import org.springframework.extensions.webscripts.TestWebScriptServer.DeleteRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.PostRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.PutRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.Response;
/**
* Unit Test to test Blog Web Script API
*
* @author mruflin
*/
public class BlogServiceTest extends BaseWebScriptTest
{
@SuppressWarnings("unused")
private static Log logger = LogFactory.getLog(BlogServiceTest.class);
private MutableAuthenticationService authenticationService;
private AuthenticationComponent authenticationComponent;
private PersonService personService;
private SiteService siteService;
private static final String USER_ONE = "UserOneSecondToo";
private static final String USER_TWO = "UserTwoSecondToo";
private static final String SITE_SHORT_NAME_BLOG = "BlogSiteShortNameTest";
private static final String COMPONENT_BLOG = "blog";
private static final String URL_BLOG_POST = "/api/blog/post/site/" + SITE_SHORT_NAME_BLOG + "/" + COMPONENT_BLOG + "/";
private static final String URL_BLOG_POSTS = "/api/blog/site/" + SITE_SHORT_NAME_BLOG + "/" + COMPONENT_BLOG + "/posts";
private static final String URL_MY_DRAFT_BLOG_POSTS = "/api/blog/site/" + SITE_SHORT_NAME_BLOG +
"/" + COMPONENT_BLOG + "/posts/mydrafts";
private static final String URL_MY_PUBLISHED_BLOG_POSTS = "/api/blog/site/" + SITE_SHORT_NAME_BLOG +
"/" + COMPONENT_BLOG + "/posts/mypublished";
private List<String> posts = new ArrayList<String>(5);
private List<String> drafts = new ArrayList<String>(5);
// General methods
@Override
protected void setUp() throws Exception
{
super.setUp();
this.authenticationService = (MutableAuthenticationService)getServer().getApplicationContext().getBean("AuthenticationService");
this.authenticationComponent = (AuthenticationComponent)getServer().getApplicationContext().getBean("authenticationComponent");
this.personService = (PersonService)getServer().getApplicationContext().getBean("PersonService");
this.siteService = (SiteService)getServer().getApplicationContext().getBean("SiteService");
// Authenticate as user
this.authenticationComponent.setCurrentUser(AuthenticationUtil.getAdminUserName());
// Create test site
// - only create the site if it doesn't already exist
SiteInfo siteInfo = this.siteService.getSite(SITE_SHORT_NAME_BLOG);
if (siteInfo == null)
{
this.siteService.createSite("BlogSitePreset", SITE_SHORT_NAME_BLOG, "BlogSiteTitle", "BlogSiteDescription", SiteVisibility.PUBLIC);
}
// Create users
createUser(USER_ONE, SiteModel.SITE_COLLABORATOR);
createUser(USER_TWO, SiteModel.SITE_COLLABORATOR);
// Do tests as inviter user
this.authenticationComponent.setCurrentUser(USER_ONE);
}
@Override
protected void tearDown() throws Exception
{
super.tearDown();
// admin user required to delete user
this.authenticationComponent.setCurrentUser(AuthenticationUtil.getAdminUserName());
// TODO don't delete them as it seems they don't get cleaned up correctly
// delete the inviter user
// personService.deletePerson(USER_ONE);
// this.authenticationService.deleteAuthentication(USER_ONE);
// personService.deletePerson(USER_TWO);
// this.authenticationService.deleteAuthentication(USER_TWO);
// delete invite site
siteService.deleteSite(SITE_SHORT_NAME_BLOG);
}
private void createUser(String userName, String role)
{
// if user with given user name doesn't already exist then create user
if (this.authenticationService.authenticationExists(userName) == false)
{
// create user
this.authenticationService.createAuthentication(userName, "password".toCharArray());
// create person properties
PropertyMap personProps = new PropertyMap();
personProps.put(ContentModel.PROP_USERNAME, userName);
personProps.put(ContentModel.PROP_FIRSTNAME, "FirstName123");
personProps.put(ContentModel.PROP_LASTNAME, "LastName123");
personProps.put(ContentModel.PROP_EMAIL, "FirstName123.LastName123@email.com");
personProps.put(ContentModel.PROP_JOBTITLE, "JobTitle123");
personProps.put(ContentModel.PROP_JOBTITLE, "Organisation123");
// create person node for user
this.personService.createPerson(personProps);
}
// add the user as a member with the given role
this.siteService.setMembership(SITE_SHORT_NAME_BLOG, userName, role);
}
// Test helper methods
private JSONObject getRequestObject(String title, String content, String[] tags, boolean isDraft)
throws Exception
{
JSONObject post = new JSONObject();
if (title != null)
{
post.put("title", title);
}
if (content != null)
{
post.put("content", content);
}
if (tags != null)
{
JSONArray arr = new JSONArray();
for(String s : tags)
{
arr.put(s);
}
post.put("tags", arr);
}
post.put("draft", isDraft);
return post;
}
private JSONObject createPost(String title, String content, String[] tags, boolean isDraft, int expectedStatus)
throws Exception
{
JSONObject post = getRequestObject(title, content, tags, isDraft);
Response response = sendRequest(new PostRequest(URL_BLOG_POSTS, post.toString(), "application/json"), expectedStatus);
if (expectedStatus != 200)
{
return null;
}
//logger.debug(response.getContentAsString());
JSONObject result = new JSONObject(response.getContentAsString());
JSONObject item = result.getJSONObject("item");
if (isDraft)
{
this.drafts.add(item.getString("name"));
}
else
{
this.posts.add(item.getString("name"));
}
return item;
}
private JSONObject updatePost(String name, String title, String content, String[] tags, boolean isDraft, int expectedStatus)
throws Exception
{
JSONObject post = getRequestObject(title, content, tags, isDraft);
Response response = sendRequest(new PutRequest(URL_BLOG_POST + name, post.toString(), "application/json"), expectedStatus);
if (expectedStatus != 200)
{
return null;
}
JSONObject result = new JSONObject(response.getContentAsString());
return result.getJSONObject("item");
}
private JSONObject getPost(String name, int expectedStatus)
throws Exception
{
Response response = sendRequest(new GetRequest(URL_BLOG_POST + name), expectedStatus);
if (expectedStatus == 200)
{
JSONObject result = new JSONObject(response.getContentAsString());
return result.getJSONObject("item");
}
else
{
return null;
}
}
private String getCommentsUrl(String nodeRef)
{
return "/api/node/" + nodeRef.replace("://", "/") + "/comments";
}
private String getCommentUrl(String nodeRef)
{
return "/api/comment/node/" + nodeRef.replace("://", "/");
}
private JSONObject createComment(String nodeRef, String title, String content, int expectedStatus)
throws Exception
{
JSONObject comment = new JSONObject();
comment.put("title", title);
comment.put("content", content);
Response response = sendRequest(new PostRequest(getCommentsUrl(nodeRef), comment.toString(), "application/json"), expectedStatus);
if (expectedStatus != 200)
{
return null;
}
//logger.debug("Comment created: " + response.getContentAsString());
JSONObject result = new JSONObject(response.getContentAsString());
return result.getJSONObject("item");
}
private JSONObject updateComment(String nodeRef, String title, String content, int expectedStatus)
throws Exception
{
JSONObject comment = new JSONObject();
comment.put("title", title);
comment.put("content", content);
Response response = sendRequest(new PutRequest(getCommentUrl(nodeRef), comment.toString(), "application/json"), expectedStatus);
if (expectedStatus != 200)
{
return null;
}
//logger.debug("Comment updated: " + response.getContentAsString());
JSONObject result = new JSONObject(response.getContentAsString());
return result.getJSONObject("item");
}
// Tests
public void testCreateDraftPost() throws Exception
{
String title = "test";
String content = "test";
JSONObject item = createPost(title, content, null, true, 200);
// check that the values
assertEquals(title, item.get("title"));
assertEquals(content, item.get("content"));
assertEquals(true, item.get("isDraft"));
// check that other user doesn't have access to the draft
this.authenticationComponent.setCurrentUser(USER_TWO);
getPost(item.getString("name"), 404);
this.authenticationComponent.setCurrentUser(USER_ONE);
// Now we'll GET my-drafts to ensure that the post is there.
Response response = sendRequest(new GetRequest(URL_MY_DRAFT_BLOG_POSTS), 200);
JSONObject result = new JSONObject(response.getContentAsString());
assertTrue("Wrong number of posts", result.length() > 0);
}
/**
* @since 4.0
*/
public void testCreateDraftPostWithTagsAndComment() throws Exception
{
String[] tags = new String[]{"foo", "bar"};
String title = "test";
String content = "test";
JSONObject item = createPost(title, content, tags, true, 200);
// check that the values
assertEquals(title, item.get("title"));
assertEquals(content, item.get("content"));
assertEquals(true, item.get("isDraft"));
JSONArray recoveredTags = (JSONArray)item.get("tags");
assertEquals("Tags size was wrong.", 2, recoveredTags.length());
List<String> recoveredTagsList = Arrays.asList(new String[]{recoveredTags.getString(0), recoveredTags.getString(1)});
assertEquals("Tags were wrong.", Arrays.asList(tags), recoveredTagsList);
// comment on the blog post.
NodeRef blogPostNode = new NodeRef(item.getString("nodeRef"));
// Currently (mid-Swift dev) there is no Java CommentService, so we have to post a comment via the REST API.
String commentsPostUrl = "/api/node/" + blogPostNode.getStoreRef().getProtocol() +
"/" + blogPostNode.getStoreRef().getIdentifier() + "/" +
blogPostNode.getId() + "/comments";
String jsonToPost = new JSONStringer().object()
.key("title").value("Commented blog title")
.key("content").value("Some content.")
.endObject().toString();
Response response = sendRequest(new PostRequest(commentsPostUrl, jsonToPost, "application/json"), 200);
// check that other user doesn't have access to the draft
this.authenticationComponent.setCurrentUser(USER_TWO);
getPost(item.getString("name"), 404);
this.authenticationComponent.setCurrentUser(USER_ONE);
// Now we'll GET my-drafts to ensure that the post is there.
response = sendRequest(new GetRequest(URL_MY_DRAFT_BLOG_POSTS), 200);
JSONObject result = new JSONObject(response.getContentAsString());
// Ensure it reports the tag correctly on GET.
JSONArray items = result.getJSONArray("items");
JSONArray tagsArray = items.getJSONObject(0).getJSONArray("tags");
assertEquals("Wrong number of tags", 2, tagsArray.length());
assertEquals("Tag wrong", tags[0], tagsArray.getString(0));
assertEquals("Tag wrong", tags[1], tagsArray.getString(1));
// Ensure the comment count is accurate
assertEquals("Wrong comment count", 1, items.getJSONObject(0).getInt("commentCount"));
// and that there is content at the commentsURL.
String commentsUrl = "/api" + items.getJSONObject(0).getString("commentsUrl");
response = sendRequest(new GetRequest(commentsUrl), 200);
// TODO Replies still not right in the Share UI.
}
public void testCreatePublishedPost() throws Exception
{
String title = "published";
String content = "content";
JSONObject item = createPost(title, content, null, false, 200);
final String postName = item.getString("name");
// check the values
assertEquals(title, item.get("title"));
assertEquals(content, item.get("content"));
assertEquals(false, item.get("isDraft"));
// check that user two has access to it as well
this.authenticationComponent.setCurrentUser(USER_TWO);
getPost(item.getString("name"), 200);
this.authenticationComponent.setCurrentUser(USER_ONE);
// Now we'll GET my-published to ensure that the post is there.
Response response = sendRequest(new GetRequest(URL_MY_PUBLISHED_BLOG_POSTS), 200);
JSONObject result = new JSONObject(response.getContentAsString());
// we should have posts.size + drafts.size together
assertEquals(this.posts.size() + this.drafts.size(), result.getInt("total"));
// Finally, we'll delete the blog-post to test the REST DELETE call.
response = sendRequest(new DeleteRequest(URL_BLOG_POST + postName), 200);
}
public void testCreateEmptyPost() throws Exception
{
JSONObject item = createPost(null, null, null, false, 200);
// check the values
assertEquals("", item.get("title"));
assertEquals("", item.get("content"));
assertEquals(false, item.get("isDraft"));
// check that user two has access to it as well
this.authenticationComponent.setCurrentUser(USER_TWO);
getPost(item.getString("name"), 200);
this.authenticationComponent.setCurrentUser(USER_ONE);
}
public void testUpdated() throws Exception
{
JSONObject item = createPost("test", "test", null, false, 200);
String name = item.getString("name");
assertEquals(false, item.getBoolean("isUpdated"));
item = updatePost(name, "new title", "new content", null, false, 200);
assertEquals(true, item.getBoolean("isUpdated"));
assertEquals("new title", item.getString("title"));
assertEquals("new content", item.getString("content"));
}
public void testUpdateWithEmptyValues() throws Exception
{
JSONObject item = createPost("test", "test", null, false, 200);
String name = item.getString("name");
assertEquals(false, item.getBoolean("isUpdated"));
item = updatePost(item.getString("name"), null, null, null, false, 200);
assertEquals("", item.getString("title"));
assertEquals("", item.getString("content"));
}
public void testPublishThroughUpdate() throws Exception
{
JSONObject item = createPost("test", "test", null, true, 200);
String name = item.getString("name");
assertEquals(true, item.getBoolean("isDraft"));
// check that user two does not have access
this.authenticationComponent.setCurrentUser(USER_TWO);
getPost(name, 404);
this.authenticationComponent.setCurrentUser(USER_ONE);
item = updatePost(name, "new title", "new content", null, false, 200);
assertEquals("new title", item.getString("title"));
assertEquals("new content", item.getString("content"));
assertEquals(false, item.getBoolean("isDraft"));
// check that user two does have access
this.authenticationComponent.setCurrentUser(USER_TWO);
getPost(name, 200);
this.authenticationComponent.setCurrentUser(USER_ONE);
}
public void testCannotDoUnpublish() throws Exception
{
JSONObject item = createPost("test", "test", null, false, 200);
String name = item.getString("name");
assertEquals(false, item.getBoolean("isDraft"));
item = updatePost(name, "new title", "new content", null, true, 400); // should return bad request
}
public void testGetAll() throws Exception
{
String url = URL_BLOG_POSTS;
Response response = sendRequest(new GetRequest(url), 200);
JSONObject result = new JSONObject(response.getContentAsString());
// we should have posts.size + drafts.size together
assertEquals(this.posts.size() + this.drafts.size(), result.getInt("total"));
}
public void testGetNew() throws Exception
{
String url = URL_BLOG_POSTS + "/new";
Response response = sendRequest(new GetRequest(url), 200);
JSONObject result = new JSONObject(response.getContentAsString());
// we should have posts.size
assertEquals(this.posts.size(), result.getInt("total"));
}
public void testGetDrafts() throws Exception
{
String url = URL_BLOG_POSTS + "/mydrafts";
Response response = sendRequest(new GetRequest(URL_BLOG_POSTS), 200);
JSONObject result = new JSONObject(response.getContentAsString());
// we should have drafts.size resultss
assertEquals(this.drafts.size(), result.getInt("total"));
// the second user should have zero
this.authenticationComponent.setCurrentUser(USER_TWO);
response = sendRequest(new GetRequest(url), 200);
result = new JSONObject(response.getContentAsString());
assertEquals(0, result.getInt("total"));
this.authenticationComponent.setCurrentUser(USER_ONE);
}
public void testMyPublished() throws Exception
{
String url = URL_BLOG_POSTS + "/mypublished";
Response response = sendRequest(new GetRequest(url), 200);
JSONObject result = new JSONObject(response.getContentAsString());
// we should have posts.size results
assertEquals(this.drafts.size(), result.getInt("total"));
// the second user should have zero
this.authenticationComponent.setCurrentUser(USER_TWO);
response = sendRequest(new GetRequest(url), 200);
result = new JSONObject(response.getContentAsString());
assertEquals(0, result.getInt("total"));
this.authenticationComponent.setCurrentUser(USER_ONE);
}
public void testComments() throws Exception
{
JSONObject item = createPost("test", "test", null, false, 200);
String name = item.getString("name");
String nodeRef = item.getString("nodeRef");
JSONObject commentOne = createComment(nodeRef, "comment", "content", 200);
JSONObject commentTwo = createComment(nodeRef, "comment", "content", 200);
// fetch the comments
Response response = sendRequest(new GetRequest(getCommentsUrl(nodeRef)), 200);
JSONObject result = new JSONObject(response.getContentAsString());
assertEquals(2, result.getInt("total"));
// add another one
JSONObject commentThree = createComment(nodeRef, "comment", "content", 200);
response = sendRequest(new GetRequest(getCommentsUrl(nodeRef)), 200);
result = new JSONObject(response.getContentAsString());
assertEquals(3, result.getInt("total"));
// delete the last comment
response = sendRequest(new DeleteRequest(getCommentUrl(commentThree.getString("nodeRef"))), 200);
response = sendRequest(new GetRequest(getCommentsUrl(nodeRef)), 200);
result = new JSONObject(response.getContentAsString());
assertEquals(2, result.getInt("total"));
JSONObject commentTwoUpdated = updateComment(commentTwo.getString("nodeRef"), "new title", "new content", 200);
assertEquals("new title", commentTwoUpdated.getString("title"));
assertEquals("new content", commentTwoUpdated.getString("content"));
}
/**
* Does some stress tests.
*
* Currently observed errors:
* 1. [repo.action.AsynchronousActionExecutionQueueImpl] Failed to execute asynchronous action: Action[ id=485211db-f117-4976-9530-ab861a19f563, node=null ]
* org.alfresco.repo.security.permissions.AccessDeniedException: Access Denied. You do not have the appropriate permissions to perform this operation.
*
* 2. JSONException, but with root cause being
* get(assocs) failed on instance of org.alfresco.repo.template.TemplateNode
* The problematic instruction:
* ----------
* ==> if person.assocs["cm:avatar"]?? [on line 4, column 7 in org/alfresco/repository/blogs/blogpost.lib.ftl]
*
* @throws Exception
*/
public void _testTagsStressTest() throws Exception
{
final List<Exception> exceptions = Collections.synchronizedList(new ArrayList<Exception>());
List<Thread> threads = new ArrayList<Thread>();
System.err.println("Creating and starting threads...");
for (int x=0; x < 3; x++)
{
Thread t = new Thread(new Runnable() {
public void run() {
// set the correct user
authenticationComponent.setCurrentUser(USER_ONE);
// now do some requests
try {
for (int y=0; y < 3; y++)
{
off_testPostTags();
off_testClearTags();
}
System.err.println("------------- SUCCEEDED ---------------");
} catch (Exception e)
{
System.err.println("------------- ERROR ---------------");
exceptions.add(e);
e.printStackTrace();
return;
}
}}
);
threads.add(t);
t.start();
}
/*for (Thread t : threads)
{
t.start();
}*/
for (Thread t : threads)
{
t.join();
}
System.err.println("------------- STACK TRACES ---------------");
for (Exception e : exceptions)
{
e.printStackTrace();
}
System.err.println("------------- STACK TRACES END ---------------");
if (exceptions.size() > 0)
{
throw exceptions.get(0);
}
}
public void off_testPostTags() throws Exception
{
String[] tags = { "first", "test" };
JSONObject item = createPost("tagtest", "tagtest", tags, false, 200);
assertEquals(2, item.getJSONArray("tags").length());
assertEquals("first", item.getJSONArray("tags").get(0));
assertEquals("test", item.getJSONArray("tags").get(1));
item = updatePost(item.getString("name"), null, null, new String[] { "First", "Test", "Second" }, false, 200);
assertEquals(3, item.getJSONArray("tags").length());
assertEquals("first", item.getJSONArray("tags").get(0));
assertEquals("test", item.getJSONArray("tags").get(1));
assertEquals("second", item.getJSONArray("tags").get(2));
}
public void off_testClearTags() throws Exception
{
String[] tags = { "abc", "def"};
JSONObject item = createPost("tagtest", "tagtest", tags, false, 200);
assertEquals(2, item.getJSONArray("tags").length());
item = updatePost(item.getString("name"), null, null, new String[0], false, 200);
assertEquals(0, item.getJSONArray("tags").length());
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.model.ForumModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
/**
* This class is a port of a previous JavaScript library used by the blog webscript containers.
*
* @author Neil Mc Erlean (based on existing JavaScript code)
* @since 4.0
*/
class CommentsLibJs
{
// TODO It will likely be refactored into the Blog REST API class framework.
private static final String COMMENTS_TOPIC_NAME = "Comments";
public static int getCommentsCount(NodeRef node, ServiceRegistry services)
{
return getComments(node, services).size();
}
/**
* Returns all comment nodes for a given node.
* @return an array of comments.
*/
public static List<ChildAssociationRef> getComments(NodeRef node, ServiceRegistry services)
{
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
NodeRef commentsFolder = getCommentsFolder(node, services);
if (commentsFolder != null)
{
List<ChildAssociationRef> children = services.getNodeService().getChildAssocs(commentsFolder, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
if (!children.isEmpty())
{
result = children;
}
}
return result;
}
/**
* Returns the folder that contains all the comments.
*
* We currently use the fm:discussable aspect where we
* add a "Comments" topic to it.
*/
public static NodeRef getCommentsFolder(NodeRef node, ServiceRegistry services)
{
//FIXME These methods are from the original JavaScript. Should use the (soon to arrive) CommentService.
NodeRef result = null;
if (services.getNodeService().hasAspect(node, ForumModel.ASPECT_DISCUSSABLE))
{
List<ChildAssociationRef> forumFolders = services.getNodeService().getChildAssocs(node, ForumModel.ASSOC_DISCUSSION, RegexQNamePattern.MATCH_ALL);
// The JavaScript was retrieving the first child under this child-assoc so we'll do the same.
NodeRef forumFolder = forumFolders.get(0).getChildRef();
List<ChildAssociationRef> topicFolder = services.getNodeService().getChildAssocs(forumFolder, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, COMMENTS_TOPIC_NAME));
result = topicFolder.isEmpty() ? null : topicFolder.get(0).getChildRef();
}
return result;
}
}

View File

@@ -0,0 +1,217 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.repo.nodelocator.CompanyHomeNodeLocator;
import org.alfresco.repo.nodelocator.NodeLocatorService;
import org.alfresco.repo.nodelocator.SitesHomeNodeLocator;
import org.alfresco.repo.nodelocator.UserHomeNodeLocator;
import org.alfresco.repo.search.QueryParameterDefImpl;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.search.QueryParameterDefinition;
import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* This class is a port of a previous JavaScript library.
*
* @author Neil Mc Erlean (based on previous JavaScript)
* @since 4.0
* @deprecated Not to be used/extended as this is likely to be refactored.
*/
public class RequestUtilsLibJs
{
//FIXME It will be refactored when the other services are ported from JavaScript to Java.
/**
* Gets the NodeRef requested based on the following templates:
*
* <pre>
* /api/blog/site/{site}/{container}/{path}/posts
* /api/blog/site/{site}/{container}/posts
* /api/blog/node/{store_type}/{store_id}/{id}/posts
* </pre>
*/
public static NodeRef getRequestNode(WebScriptRequest req, ServiceRegistry services)
{
NodeRef result = null;
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
// If the template args contains a "store_type" then we we have a standard NodeRef URI template pattern
// check whether we got a node reference or a site related uri
final String storeType = templateVars.get("store_type");
final String site = templateVars.get("site");
if (storeType != null)
{
result = findFromReference(templateVars, services);
}
else if (site != null)
{
result = findNodeInSite(templateVars, services);
}
else
{
throw new WebScriptException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unknown request parameters (webscript incorrectly configured?)");
}
if (!services.getNodeService().exists(result))
{
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find node: " + result.toString());
}
return result;
}
private static NodeRef findFromReference(final Map<String, String> templateVars, ServiceRegistry services)
{
NodeRef result = null;
String nodeRefString = templateVars.get("store_type") + "://" + templateVars.get("store_id") + "/" + templateVars.get("id");
// These webscripts support some non-standard NodeRef URI constructions.
NodeLocatorService nodeLocatorService = services.getNodeLocatorService();
if (nodeRefString.equals("alfresco://company/home"))
{
result = nodeLocatorService.getNode(CompanyHomeNodeLocator.NAME, null, null);
}
else if (nodeRefString.equals("alfresco://user/home"))
{
result = nodeLocatorService.getNode(UserHomeNodeLocator.NAME, null, null);
}
else if (nodeRefString.equals("alfresco://sites/home"))
{
result = nodeLocatorService.getNode(SitesHomeNodeLocator.NAME, null, null);
}
else if (NodeRef.isNodeRef(nodeRefString))
{
result = new NodeRef(nodeRefString);
}
else
{
// result = new Nodesearch.findNode(nodeRef);
}
if (result == null)
{
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Node " + nodeRefString + "does not exist");
}
return result;
}
/**
* Returns the node as specified by the given arguments.
*
* @param siteId the site for which a node is requested
* @param containerId the component to look in for the node.
* @param path a path to the node. Returns the root node in case path is null or ''
* return null in case no node can be found for the given path
* @return the node or a json error in case the node could not be fetched. Check with .
*/
private static NodeRef findNodeInSite(final Map<String, String> templateVars, ServiceRegistry services)
{
final String siteId = templateVars.get("site");
final String containerId = templateVars.get("container");
String path = templateVars.get("path");
if (path == null) path = "";
SiteInfo site = services.getSiteService().getSite(siteId);
if (site == null)
{
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Site not found: '" + siteId + "'");
}
NodeRef node = services.getSiteService().getContainer(siteId, containerId);
if (node == null)
{
node = services.getSiteService().createContainer(siteId, containerId, null, null);
if (node == null)
{
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to fetch container '" + containerId + "' of site '" + siteId + "'. (No write permission?)");
}
}
// try to fetch the the path is there is any
if (path != null && !path.isEmpty())
{
node = childByNamePath(path, node, services);
if (node == null)
{
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "No node found for the given path: \"" + path + "\" in container " + containerId + " of site " + siteId);
}
}
return node;
}
/**
* Gets a descendant node by navigating a cm:name-based path e.g. /QA/Testing/Docs
*
* @see ScriptNode#childByNamePath(String)
*/
private static NodeRef childByNamePath(String path, NodeRef rootNode, ServiceRegistry services)
{
// This is based partially on ScriptNode.childByNamePath, but supports less path variations.
NodeRef result = null;
QName nodeType = services.getNodeService().getType(rootNode);
if (services.getDictionaryService().isSubClass(nodeType, ContentModel.TYPE_FOLDER))
{
/**
* The current node is a folder.
* optimized code path for cm:folder and sub-types supporting getChildrenByName() method
*/
StringTokenizer t = new StringTokenizer(path, "/");
if (t.hasMoreTokens())
{
result = rootNode;
while (t.hasMoreTokens() && result != null)
{
String name = t.nextToken();
try
{
result = services.getNodeService().getChildByName(result, ContentModel.ASSOC_CONTAINS, name);
}
catch (AccessDeniedException ade)
{
result = null;
}
}
}
}
return result;
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.blog;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.web.scripts.blogs.AbstractBlogWebScript;
import org.alfresco.repo.web.scripts.blogs.RequestUtilsLibJs;
import org.alfresco.service.cmr.repository.NodeRef;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* This class is the controller for the blog.get web script.
*
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public class BlogGet extends AbstractBlogWebScript
{
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
Map<String, Object> model = new HashMap<String, Object>();
// get requested node
NodeRef node = RequestUtilsLibJs.getRequestNode(req, services);
model.put(ITEM, node);
return model;
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.blog;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.BlogIntegrationModel;
import org.alfresco.repo.web.scripts.blogs.AbstractBlogWebScript;
import org.alfresco.repo.web.scripts.blogs.BlogLibJs;
import org.alfresco.repo.web.scripts.blogs.RequestUtilsLibJs;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
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.WebScriptRequest;
/**
* This class is the controller for the blog.get web script.
*
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public class BlogPut extends AbstractBlogWebScript
{
@SuppressWarnings("deprecation")
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
Map<String, Object> model = new HashMap<String, Object>();
// get requested node
NodeRef node = RequestUtilsLibJs.getRequestNode(req, services);
// parse the JSON
JSONObject json = null;
try
{
json = new JSONObject(new JSONTokener(req.getContent().getContent()));
} catch (JSONException jsonX)
{
throw new AlfrescoRuntimeException("Could not parse JSON", jsonX);
} catch (IOException iox)
{
throw new AlfrescoRuntimeException("Could not parse JSON", iox);
}
updateBlog(node, json);
model.put("item", node);
return model;
}
/**
* Creates a post inside the passed forum node.
*/
@SuppressWarnings("deprecation")
private void updateBlog(NodeRef node, JSONObject json)
{
Map<QName, Serializable> arr = BlogLibJs.getBlogPropertiesArray(json);
if (nodeService.hasAspect(node, BlogIntegrationModel.ASPECT_BLOG_DETAILS))
{
nodeService.setProperties(node, arr);
}
else
{
nodeService.addAspect(node, BlogIntegrationModel.ASPECT_BLOG_DETAILS, arr);
}
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.post;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.web.scripts.blogs.AbstractBlogWebScript;
import org.alfresco.repo.web.scripts.blogs.RequestUtilsLibJs;
import org.alfresco.service.cmr.activities.ActivityPostService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.json.JSONException;
import org.json.JSONStringer;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* This class is the controller for the blog-posts.get web script.
*
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public class BlogPostDelete extends AbstractBlogWebScript
{
private ActivityPostService activityPostService;
public void setActivityPostService(ActivityPostService activityPostService)
{
this.activityPostService = activityPostService;
}
@SuppressWarnings("deprecation")
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
Map<String, Object> model = new HashMap<String, Object>();
// get requested node
NodeRef node = RequestUtilsLibJs.getRequestNode(req, services);
// Map<String, Object> item = BlogPostLibJs.getBlogPostData(node, services);
final String title = (String) nodeService.getProperty(node, ContentModel.PROP_TITLE);
final String site = req.getServiceMatch().getTemplateVars().get("site");
final String page = req.getParameter("page");
final boolean isDraftBlogPost = blogService.isDraftBlogPost(node);
nodeService.deleteNode(node);
model.put("message", "Node " + node + " deleted");
if (site != null && !isDraftBlogPost)
{
sendActivityReport(title, site, page);
}
return model;
}
private void sendActivityReport(final String title, final String site,
final String page)
{
String data = null;
try
{
data = new JSONStringer()
.object()
.key(TITLE).value(title)
.key(PAGE).value(page)
.endObject().toString();
} catch (JSONException e)
{
// Intentionally empty
}
if (data != null)
{
activityPostService.postActivity("org.alfresco.blog.post-deleted", site, "blog", data);
}
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.post;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.web.scripts.blogs.AbstractBlogWebScript;
import org.alfresco.repo.web.scripts.blogs.BlogPostLibJs;
import org.alfresco.repo.web.scripts.blogs.RequestUtilsLibJs;
import org.alfresco.service.cmr.repository.NodeRef;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* This class is the controller for the blog-posts.get web script.
*
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public class BlogPostGet extends AbstractBlogWebScript
{
@SuppressWarnings("deprecation")
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
Map<String, Object> model = new HashMap<String, Object>();
// get requested node
NodeRef node = RequestUtilsLibJs.getRequestNode(req, services);
Map<String, Object> item = BlogPostLibJs.getBlogPostData(node, services);
model.put("item", item);
model.put("externalBlogConfig", BlogPostLibJs.hasExternalBlogConfiguration(node, services));
int contentLength = -1;
String arg = req.getParameter("contentLength");
if (arg != null)
{
try
{
contentLength = Integer.parseInt(arg);
}
catch (NumberFormatException ignored)
{
// Intentionally empty
}
}
model.put("contentLength", contentLength);
return model;
}
}

View File

@@ -0,0 +1,166 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.posts;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.repo.web.scripts.blogs.AbstractBlogWebScript;
import org.alfresco.repo.web.scripts.blogs.BlogPostLibJs;
import org.alfresco.repo.web.scripts.blogs.RequestUtilsLibJs;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.Pair;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public abstract class AbstractGetBlogWebScript extends AbstractBlogWebScript
{
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
Map<String, Object> model = new HashMap<String, Object>();
// get requested node
NodeRef node = RequestUtilsLibJs.getRequestNode(req, services);
// process additional parameters. <index, count>
PagingRequest pagingReq = parsePagingParams(req);
// begin and end date.
// Legacy note: these dates are URL query parameters in int form.
Date fromDate = parseDateParam(req, "fromDate");
Date toDate = parseDateParam(req, "toDate");
String tag = req.getParameter("tag");
if (tag != null && tag.length() == 0) tag = null;
// One webscript (blog-posts-new.get) uses a 'numdays' parameter as a 'fromDate'.
// This is a hacky solution to this special case. FIXME
if (this.getClass().equals(BlogPostsNewGet.class))
{
// Default is for 'now' minus seven days.
final int oneDayInMilliseconds = 24 * 60 * 60 * 1000;
final long sevenDaysInMilliseconds = 7 * oneDayInMilliseconds;
fromDate = new Date(System.currentTimeMillis() - sevenDaysInMilliseconds);
// But if there is a numdays parameter then that changes the fromDate
String numDays = req.getServiceMatch().getTemplateVars().get("numdays");
if (numDays != null)
{
Integer numDaysInt = Integer.parseInt(numDays);
fromDate = new Date(System.currentTimeMillis() - (numDaysInt * oneDayInMilliseconds));
}
}
// fetch and assign the data
PagingResults<BlogPostInfo> blogPostList = getBlogPostList(node, fromDate, toDate,
tag, pagingReq);
createFtlModel(req, model, node, pagingReq, blogPostList);
return model;
}
protected void createFtlModel(WebScriptRequest req, Map<String, Object> model, NodeRef node, PagingRequest pagingReq,
PagingResults<BlogPostInfo> blogPostList)
{
Map<String, Object> blogPostsData = new HashMap<String, Object>();
final Pair<Integer, Integer> totalResultCount = blogPostList.getTotalResultCount();
//FIXME What to do? null
blogPostsData.put("total", totalResultCount.getFirst());
blogPostsData.put("pageSize", pagingReq.getMaxItems());
blogPostsData.put("startIndex", pagingReq.getSkipCount());
blogPostsData.put("itemCount", blogPostList.getPage().size());
List<Map<String, Object>> blogPostDataSets = new ArrayList<Map<String, Object>>(blogPostList.getPage().size());
for (BlogPostInfo postInfo : blogPostList.getPage())
{
Map<String, Object> data = BlogPostLibJs.getBlogPostData(postInfo.getNodeRef(), services);
blogPostDataSets.add(data);
}
blogPostsData.put("items", blogPostDataSets);
model.put("data", blogPostsData);
// fetch the contentLength param
String contentLengthStr = req.getServiceMatch().getTemplateVars().get("contentLength");
int contentLength = contentLengthStr == null ? -1 : Integer.parseInt(contentLengthStr);
model.put("contentLength", contentLength);
// assign the blog node
model.put("blog", node);
model.put("externalBlogConfig", BlogPostLibJs.hasExternalBlogConfiguration(node, services));
}
private PagingRequest parsePagingParams(WebScriptRequest req)
{
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
String startIndexStr = templateVars.get("startIndex");
String pageSizeStr = templateVars.get("pageSize");
int startIndex = 0;
int pageSize = 10;
if (startIndexStr != null)
{
startIndex = Integer.parseInt(startIndexStr);
}
if (pageSizeStr != null)
{
pageSize = Integer.parseInt(pageSizeStr);
}
return new PagingRequest(startIndex, pageSize, null);
}
private Date parseDateParam(WebScriptRequest req, String paramName)
{
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
String dateStr = templateVars.get(paramName);
Date result = null;
if (dateStr != null)
{
result = new Date(Integer.parseInt(dateStr));
}
return result;
}
/**
* Fetches all posts of the given blog
*/
private PagingResults<BlogPostInfo> getBlogPostList(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq)
{
PagingResults<BlogPostInfo> results = getBlogResultsImpl(node, fromDate, toDate, tag, pagingReq);
return results;
}
protected abstract PagingResults<BlogPostInfo> getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq);
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.posts;
import java.util.Date;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* This class is the controller for the blog-posts.get web script.
*
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public class BlogPostsGet extends AbstractGetBlogWebScript
{
@SuppressWarnings("deprecation")
@Override
protected PagingResults<BlogPostInfo> getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq)
{
// This intentionally uses the deprecated method in the foundation service.
// In fact the method is there specifically for this class.
return blogService.getMyDraftsAndAllPublished(node, fromDate, toDate, tag, pagingReq);
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.posts;
import java.util.Date;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* This class is the controller for the blog-posts-mydrafts.get web script.
* Based on the original JavaScript webscript controller
*
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public class BlogPostsMyDraftsGet extends AbstractGetBlogWebScript
{
@Override
protected PagingResults<BlogPostInfo> getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq)
{
return blogService.getDrafts(node, AuthenticationUtil.getFullyAuthenticatedUser(), pagingReq);
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.posts;
import java.util.Date;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* This class is the controller for the blog-posts-mypublished.get web script.
*
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public class BlogPostsMyPublishedGet extends AbstractGetBlogWebScript
{
@Override
protected PagingResults<BlogPostInfo> getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq)
{
String fullyAuthenticatedUser = AuthenticationUtil.getFullyAuthenticatedUser();
return blogService.getPublished(node, fromDate, toDate, fullyAuthenticatedUser, pagingReq);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.posts;
import java.util.Date;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* This class is the controller for the blog-posts-publishedext.get web script.
*
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public class BlogPostsNewGet extends AbstractGetBlogWebScript
{
@Override
protected PagingResults<BlogPostInfo> getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq)
{
return blogService.getPublished(node, fromDate, toDate, null, pagingReq);
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.posts;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* This class is the controller for the blog-posts-mypublished.get web script.
*
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public class BlogPostsPerMonthGet extends AbstractGetBlogWebScript
{
@Override
protected PagingResults<BlogPostInfo> getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq)
{
return blogService.getPublished(node, fromDate, toDate, null, pagingReq);
}
@Override
protected void createFtlModel(WebScriptRequest req, Map<String, Object> model, NodeRef node, PagingRequest pagingReq, PagingResults<BlogPostInfo> blogPostList)
{
model.put(DATA, getBlogPostMonths(blogPostList));
}
/**
* Ported from blog-posts-per-month.get.js
*/
@SuppressWarnings("deprecation")
private Date getBeginOfMonthDate(Date date)
{
//TODO These date processing methods are copied almost verbatim from JavaScript to preserve behaviour.
// However they should be updated to use java.util.Calendar as the current implementation assumes a Gregorian calendar.
Calendar calendar = Calendar.getInstance();
calendar.set(date.getYear(), date.getMonth(), 1);
return calendar.getTime();
}
/**
* Returns the date representing the last second of a month (23:59:59)
* Ported from blog-posts-per-month.get.js
*/
@SuppressWarnings("deprecation")
private Date getEndOfMonthDate(Date date)
{
Calendar calendar = Calendar.getInstance();
calendar.set(date.getYear(), date.getMonth(), date.getDay());
// In Gregorian calendar, this would be 31 for January, 30 for March, 28 or 29 for February.
int lastDayOfSpecifiedMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
calendar.set(date.getYear(), date.getMonth(), lastDayOfSpecifiedMonth, 23, 59, 59);
return calendar.getTime();
}
/**
* Create an object containing information about the month specified by date.
* Ported from blog-posts-per-month.get.js
*/
@SuppressWarnings("deprecation")
private Map<String, Object> getMonthDataObject(Date date)
{
Map<String, Object> data = new HashMap<String, Object>();
data.put("year", date.getYear() + 1900);
data.put("month", date.getMonth());
data.put("firstPostInMonth", date);
data.put("beginOfMonth", getBeginOfMonthDate(date));
data.put("endOfMonth", getEndOfMonthDate(date));
data.put("count", 1);
return data;
}
/**
* Fetches data for each month for which posts exist, plus the count of each.
* Note: If no posts could be found, this method will return the current month
* but with a count of posts equals zero.
* Ported from blog-posts-per-month.get.js
*/
@SuppressWarnings("deprecation")
private List<Map<String, Object>> getBlogPostMonths(PagingResults<BlogPostInfo> nodes)
{
// will hold the months information
List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
// do we have posts?
if (!nodes.getPage().isEmpty())
{
int currYear = -1;
int currMonth = -1;
Map<String, Object> currData = null;
for (int x = 0; x < nodes.getPage().size(); x++)
{
NodeRef node = nodes.getPage().get(x).getNodeRef();
Date date = (Date) nodeService.getProperty(node, ContentModel.PROP_PUBLISHED);
// is this a new month?
if (currYear != date.getYear() + 1900 || currMonth != date.getMonth())
{
currYear = date.getYear() + 1900;
currMonth = date.getMonth();
currData = getMonthDataObject(date);
data.add(currData);
}
// otherwise just increment the counter
else
{
Object countObj = currData.get("count");
Integer countInt = countObj == null ? 0 : (Integer)countObj;
currData.put("count", countInt + 1);
}
}
}
// if not, add the current month with count = 0
else
{
Map<String, Object> emptyData = getMonthDataObject(new Date());
emptyData.put("count", 0);
data.add(emptyData);
}
return data;
}
}

View File

@@ -0,0 +1,301 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.posts;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.web.scripts.blogs.AbstractBlogWebScript;
import org.alfresco.repo.web.scripts.blogs.BlogPostLibJs;
import org.alfresco.repo.web.scripts.blogs.RequestUtilsLibJs;
import org.alfresco.service.cmr.activities.ActivityPostService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;
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;
/**
* This class is the controller for the blog-posts.post web script.
*
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public class BlogPostsPost extends AbstractBlogWebScript
{
// Injected services
private ActivityPostService activityPostService;
private TaggingService taggingService;
public void setActivityPostService(ActivityPostService activityPostService)
{
this.activityPostService = activityPostService;
}
public void setTaggingService(TaggingService taggingService)
{
this.taggingService = taggingService;
}
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
Map<String, Object> model = new HashMap<String, Object>();
JsonParams jsonPostParams = parsePostParams(req);
NodeRef node = RequestUtilsLibJs.getRequestNode(req, services);
ensureTagScope(node);
NodeRef post = createBlogPost(jsonPostParams, node);
Map<String, Object> blogPostData = BlogPostLibJs.getBlogPostData(post, services);
model.put(ITEM, blogPostData);
model.put(EXTERNAL_BLOG_CONFIG, BlogPostLibJs.hasExternalBlogConfiguration(node, services));
boolean isDraft = blogPostData.get(ITEM) != null &&
((Boolean)blogPostData.get(ITEM)).booleanValue();
if (jsonPostParams.getSite() != null &&
jsonPostParams.getContainer() != null &&
jsonPostParams.getPage() != null &&
!isDraft)
{
final NodeRef nodeParam = (NodeRef)blogPostData.get(NODE);
String postNodeName = (String)nodeService.getProperty(nodeParam, ContentModel.PROP_NAME);
String postNodeTitle = (String)nodeService.getProperty(nodeParam, ContentModel.PROP_TITLE);
String data = null;
try
{
data = new JSONStringer()
.object()
.key(TITLE).value(postNodeTitle)
.key(PAGE).value(jsonPostParams.getPage() + "?postId=" + postNodeName)
.endObject().toString();
} catch (JSONException e)
{
// Intentionally empty
}
if (data != null)
{
activityPostService.postActivity("org.alfresco.blog.post-created", jsonPostParams.getSite(), "blog", data);
}
}
return model;
}
private JsonParams parsePostParams(WebScriptRequest req)
{
try
{
JSONObject json = new JSONObject(new JSONTokener(req.getContent().getContent()));
JsonParams result = new JsonParams();
if (json.has(TITLE))
{
result.setTitle(json.getString(TITLE));
}
if (json.has(CONTENT))
{
result.setContent(json.getString(CONTENT));
}
if (json.has(DRAFT))
{
result.setIsDraft(json.getString(DRAFT));
}
// If there are no tags, this is a java.lang.String "".
// If there are any tags, it's a JSONArray of strings. One or more.
if (json.has(TAGS))
{
Object tagsObj = json.get(TAGS);
List<String> tags = new ArrayList<String>();
if (tagsObj instanceof JSONArray)
{
JSONArray tagsJsonArray = (JSONArray)tagsObj;
for (int i = 0; i < tagsJsonArray.length(); i++)
{
tags.add(tagsJsonArray.getString(i));
}
}
else
{
tags.add(tagsObj.toString());
}
result.setTags(tags);
}
if (json.has(SITE))
{
result.setSite(json.getString(SITE));
}
if (json.has(PAGE))
{
result.setPage(json.getString(PAGE));
}
if (json.has(CONTAINER))
{
result.setContainer(json.getString(CONTAINER));
}
return result;
}
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);
}
}
/**
* Taken from JS
* @param node
*/
private void ensureTagScope(NodeRef node)
{
if (!taggingService.isTagScope(node))
{
taggingService.addTagScope(node);
}
// also check the parent (the site!)
NodeRef parent = nodeService.getPrimaryParent(node).getParentRef();
if (!taggingService.isTagScope(parent))
{
taggingService.addTagScope(parent);
}
}
/**
* Creates a blog post
*/
private NodeRef createBlogPost(JsonParams jsonParams, NodeRef blogNode)
{
String titleParam = jsonParams.getTitle() == null ? "" : jsonParams.getTitle();
String contentParam = jsonParams.getContent() == null ? "" : jsonParams.getContent();
boolean isDraftParam = jsonParams.getIsDraft() == null ? false : Boolean.parseBoolean(jsonParams.getIsDraft());
List<String> tagsParam = new ArrayList<String>();
if (jsonParams.getTags() != null)
{
tagsParam.addAll(jsonParams.getTags());
}
ChildAssociationRef newPostNode = blogService.createBlogPost(blogNode, titleParam, contentParam, isDraftParam);
// Ignore empty string tags
List<String> nonEmptyTags = new ArrayList<String>();
for (String tag : tagsParam)
{
if (!tag.trim().isEmpty())
{
nonEmptyTags.add(tag);
}
}
if (!nonEmptyTags.isEmpty())
{
taggingService.setTags(newPostNode.getChildRef(), nonEmptyTags);
}
return newPostNode.getChildRef();
}
/**
* A simple POJO class for the parsed JSON from the POST body.
*/
class JsonParams
{
private String title;
private String content;
private String isDraft; //This is a String, not a boolean
private List<String> tags;
private String site;
private String container;
private String page;
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getContent()
{
return content;
}
public void setContent(String content)
{
this.content = content;
}
public String getIsDraft()
{
return isDraft;
}
public void setIsDraft(String isDraft)
{
this.isDraft = isDraft;
}
public List<String> getTags()
{
return tags;
}
public void setTags(List<String> tags)
{
this.tags = tags;
}
public String getSite()
{
return site;
}
public void setSite(String site)
{
this.site = site;
}
public String getContainer()
{
return container;
}
public void setContainer(String container)
{
this.container = container;
}
public String getPage()
{
return page;
}
public void setPage(String page)
{
this.page = page;
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2005-2011 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.blogs.posts;
import java.util.Date;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* This class is the controller for the blog-posts-publishedext.get web script.
*
* @author Neil Mc Erlean (based on existing JavaScript webscript controllers)
* @since 4.0
*/
public class BlogPostsPublishedExtGet extends AbstractGetBlogWebScript
{
@Override
protected PagingResults<BlogPostInfo> getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq)
{
return blogService.getPublishedExternally(node, pagingReq);
}
}