diff --git a/config/alfresco/blogs/web-scripts-blog-context.xml b/config/alfresco/blogs/web-scripts-blog-context.xml new file mode 100644 index 0000000000..f7541298d8 --- /dev/null +++ b/config/alfresco/blogs/web-scripts-blog-context.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/blog/blog.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/blog/blog.get.js deleted file mode 100644 index ba4a47f482..0000000000 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/blog/blog.get.js +++ /dev/null @@ -1,16 +0,0 @@ - - - -function main() -{ - // get requested node - var node = getRequestNode(); - if (status.getCode() != status.STATUS_OK) - { - return; - } - - model.item = getBlogData(node); -} - -main(); diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/blog/blog.put.json.js b/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/blog/blog.put.json.js deleted file mode 100644 index 850e23639b..0000000000 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/blog/blog.put.json.js +++ /dev/null @@ -1,43 +0,0 @@ - - - -/** - * Creates a post inside the passed forum node. - */ -function updateBlog(node) -{ - var arr = getBlogPropertiesArray(); - - // check whether we already have the aspect added to the node. - if (node.hasAspect(BLOG_DETAILS_ASPECT)) - { - for (propName in arr) - { - node.properties[propName] = arr[propName]; - } - } - else - { - // if not, add the aspect on the fly - node.addAspect(BLOG_DETAILS_ASPECT, arr); - } - - node.save(); -} - -function main() -{ - // get requested node - var node = getRequestNode(); - if (status.getCode() != status.STATUS_OK) - { - return; - } - - // update blog - updateBlog(node); - - model.item = getBlogData(node); -} - -main(); diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/post/blog-post.delete.js b/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/post/blog-post.delete.js deleted file mode 100644 index b76b3db12a..0000000000 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/post/blog-post.delete.js +++ /dev/null @@ -1,47 +0,0 @@ - - - -/** - * Deletes a blog post node. - */ -function deleteBlogPost(postNode) -{ - // delete the node - var nodeRef = postNode.nodeRef; - var isDeleted = postNode.remove(); - if (!isDeleted) - { - status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "Unable to delete node: " + nodeRef); - return; - } - model.message = "Node " + nodeRef + " deleted"; -} - -function main() -{ - // get requested node - var node = getRequestNode(); - if (status.getCode() != status.STATUS_OK) - { - return; - } - - var item = getBlogPostData(node); - - var title = node.properties.title; - var tags = node.properties.tags; - - deleteBlogPost(node); - - if (url.templateArgs.site !== undefined && !item.isDraft) - { - var data = - { - title: title, - page: decodeURIComponent(args["page"]) - } - activities.postActivity("org.alfresco.blog.post-deleted", url.templateArgs.site, "blog", jsonUtils.toJSONString(data)); - } -} - -main(); diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/post/blog-post.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/post/blog-post.get.js deleted file mode 100644 index efceef3521..0000000000 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/post/blog-post.get.js +++ /dev/null @@ -1,22 +0,0 @@ - - - -function main() -{ - // get requested node - var node = getRequestNode(); - if (status.getCode() != status.STATUS_OK) - { - return; - } - - // assign data - model.item = getBlogPostData(node); - model.externalBlogConfig = hasExternalBlogConfiguration(node); - - // fetch the contentLength param - var contentLength = args["contentLength"] != undefined ? parseInt(args["contentLength"]) : -1; - model.contentLength = isNaN(contentLength) ? -1 : contentLength; -} - -main(); diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-mydrafts.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-mydrafts.get.js deleted file mode 100644 index 5a7a41ebb3..0000000000 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-mydrafts.get.js +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -/** - * Fetches all posts of the given blog - */ -function getBlogPostList(node, index, count) -{ - // query information - var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\" " + - " +PATH:\"" + node.qnamePath + "/*\" "; - luceneQuery += " +(@\\{http\\://www.alfresco.org/model/content/1.0\\}content.mimetype:application/octet-stream OR"; - luceneQuery += " @\\{http\\://www.alfresco.org/model/content/1.0\\}content.mimetype:text/html)" - - - // add the drafts part - luceneQuery += " -ISNOTNULL:\"{http://www.alfresco.org/model/content/1.0}published\" " + - " +@cm\\:creator:\"" + person.properties.userName + "\""; - - var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created"; - - // get the data - return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getBlogPostData); -} - -function main() -{ - // get requested node - var node = getRequestNode(); - if (status.getCode() != status.STATUS_OK) - { - return; - } - - // process additional parameters - var index = args["startIndex"] != undefined ? parseInt(args["startIndex"]) : 0; - var count = args["pageSize"] != undefined ? parseInt(args["pageSize"]) : 10; - - // fetch and assign the data - model.data = getBlogPostList(node, index, count); - - // fetch the contentLength param - var contentLength = args["contentLength"] != undefined ? parseInt(args["contentLength"]) : -1; - model.contentLength = isNaN(contentLength) ? -1 : contentLength; - - // assign the blog node - model.blog = node; - model.externalBlogConfig = hasExternalBlogConfiguration(node); -} - -main(); diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-mypublished.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-mypublished.get.js deleted file mode 100644 index 8b609b7d08..0000000000 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-mypublished.get.js +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -/** - * Fetches all posts of the given blog - */ -function getBlogPostList(node, index, count) -{ - // query information - var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" + - " +PATH:\"" + node.qnamePath + "/*\" "; - luceneQuery += " +(@\\{http\\://www.alfresco.org/model/content/1.0\\}content.mimetype:application/octet-stream OR"; - luceneQuery += " @\\{http\\://www.alfresco.org/model/content/1.0\\}content.mimetype:text/html)" - - // exclude drafts - luceneQuery += " +ISNOTNULL:\"{http://www.alfresco.org/model/content/1.0}published\" " + - " +@cm\\:creator:\"" + person.properties.userName + "\""; - - - var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}published"; - - // get the data - return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getBlogPostData); -} - -function main() -{ - // get requested node - var node = getRequestNode(); - if (status.getCode() != status.STATUS_OK) - { - return; - } - - // process additional parameters - var index = args["startIndex"] != undefined ? parseInt(args["startIndex"]) : 0; - var count = args["pageSize"] != undefined ? parseInt(args["pageSize"]) : 10; - - // fetch and assign the data - model.data = getBlogPostList(node, index, count); - - // fetch the contentLength param - var contentLength = args["contentLength"] != undefined ? parseInt(args["contentLength"]) : -1; - model.contentLength = isNaN(contentLength) ? -1 : contentLength; - - // assign the blog node - model.blog = node; - model.externalBlogConfig = hasExternalBlogConfiguration(node); -} - -main(); diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-new.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-new.get.js deleted file mode 100644 index 4d4fc1f86d..0000000000 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-new.get.js +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -const DEFAULT_NUM_DAYS = 7; - -/** - * Fetches all posts of the given blog - */ -function getBlogPostList(node, numdays, index, count) -{ - var fromDate = getTodayMinusXDays(numdays); - - // query information - var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" + - " +PATH:\"" + node.qnamePath + "/*\" " + - " +ISNOTNULL:\"{http://www.alfresco.org/model/content/1.0}published\" " + - getCreationDateRangeQuery(fromDate, null); - - var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}published"; - - // get the data - return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getBlogPostData); -} - -function main() -{ - // get requested node - var node = getRequestNode(); - if (status.getCode() != status.STATUS_OK) - { - return; - } - - // process additional parameters - var index = args["startIndex"] != undefined ? parseInt(args["startIndex"]) : 0; - var count = args["pageSize"] != undefined ? parseInt(args["pageSize"]) : 10; - var numdays = args["numdays"] != undefined ? parseInt(args["numdays"]) : DEFAULT_NUM_DAYS; - - // fetch and assign the data - model.data = getBlogPostList(node, numdays, index, count); - - // fetch the contentLength param - var contentLength = args["contentLength"] != undefined ? parseInt(args["contentLength"]) : -1; - model.contentLength = isNaN(contentLength) ? -1 : contentLength; - - // assign the blog node - model.blog = node; - model.externalBlogConfig = hasExternalBlogConfiguration(node); -} - -main(); diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-per-month.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-per-month.get.js deleted file mode 100644 index 899812591c..0000000000 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-per-month.get.js +++ /dev/null @@ -1,108 +0,0 @@ - - - -/** - * Returns the date representing the begin of a month (the first day at 00:00:00) - */ -function getBeginOfMonthDate(date) -{ - return new Date(date.getFullYear(), date.getMonth(), 1); -} - -/** - * Returns the date representing the last second of a month (23:59:59) - */ -function getEndOfMonthDate(date) -{ - var year = date.getFullYear(); - var month = date.getMonth(); - var beginOfNextMonth = new Date(year, month + 1, 1); // will increment year if month > 11 - return new Date(beginOfNextMonth.getTime() - 1); // one less to get the last millisecond of the previous day -} - -/** - * Create an object containing information about the month specified by date. - */ -function getMonthDataObject(date) -{ - var data = {}; - data.year = date.getFullYear(); - data.month = date.getMonth(); - data.firstPostInMonth = date; - data.beginOfMonth = getBeginOfMonthDate(date); - data.endOfMonth = getEndOfMonthDate(date); - data.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. - */ -function getBlogPostMonths(node) -{ - // query information - var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" + - " +PATH:\"" + node.qnamePath + "/*\" " + - " +ISNOTNULL:\"{http://www.alfresco.org/model/content/1.0}published\" "; - luceneQuery += " +(@\\{http\\://www.alfresco.org/model/content/1.0\\}content.mimetype:application/octet-stream OR"; - luceneQuery += " @\\{http\\://www.alfresco.org/model/content/1.0\\}content.mimetype:text/html)" - - - var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}published"; - nodes = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, true); - - // will hold the months information - var data = new Array(); - - // do we have posts? - if (nodes.length > 0) - { - var currYear = -1; - var currMonth = -1; - var currData = null; - for (var x=0; x < nodes.length; x++) - { - var date = nodes[x].properties["cm:published"]; - - // is this a new month? - if (currYear != date.getFullYear() || currMonth != date.getMonth()) - { - currYear = date.getFullYear(); - currMonth = date.getMonth(); - currData = getMonthDataObject(date); - data.push(currData); - } - // otherwise just increment the counter - else - { - currData.count += 1; - } - } - } - // if not, add the current month with count = 0 - else - { - var emptyData = getMonthDataObject(new Date()); - emptyData.count = 0; - data.push(emptyData); - } - - return data; -} - -function main() -{ - // get requested node - var node = getRequestNode(); - if (status.getCode() != status.STATUS_OK) - { - return; - } - - // fetch the months - model.data = getBlogPostMonths(node); -} - -main(); diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-publishedext.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-publishedext.get.js deleted file mode 100644 index 1c73a4bf56..0000000000 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts-publishedext.get.js +++ /dev/null @@ -1,51 +0,0 @@ - - - - - -/** - * Fetches all posts of the given blog - */ -function getBlogPostList(node, index, count) -{ - // query information - var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" + - " +PATH:\"" + node.qnamePath + "/*\" "; - luceneQuery += " +(@\\{http\\://www.alfresco.org/model/content/1.0\\}content.mimetype:application/octet-stream OR"; - luceneQuery += " @\\{http\\://www.alfresco.org/model/content/1.0\\}content.mimetype:text/html)" - - // add the drafts part - luceneQuery += "+ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}blogPost\" " - - var sortAttribute = "@{http://www.alfresco.org/model/blogintegration/1.0}posted"; - - // get the data - return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getBlogPostData); -} - -function main() -{ - // get requested node - var node = getRequestNode(); - if (status.getCode() != status.STATUS_OK) - { - return; - } - - // process additional parameters - var index = args["startIndex"] != undefined ? parseInt(args["startIndex"]) : 0; - var count = args["pageSize"] != undefined ? parseInt(args["pageSize"]) : 10; - - // fetch and assign the data - model.data = getBlogPostList(node, index, count); - - // fetch the contentLength param - var contentLength = args["contentLength"] != undefined ? parseInt(args["contentLength"]) : -1; - model.contentLength = isNaN(contentLength) ? -1 : contentLength; - - // assign the blog node - model.blog = node; - model.externalBlogConfig = hasExternalBlogConfiguration(node); -} - -main(); diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts.get.js b/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts.get.js deleted file mode 100644 index 3d71b179c8..0000000000 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts.get.js +++ /dev/null @@ -1,92 +0,0 @@ - - - - - -/** - * Fetches all posts of the given blog - */ -function getBlogPostList(node, fromDate, toDate, tag, index, count) -{ - // query information - var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" + - " +PATH:\"" + node.qnamePath + "/*\""; - luceneQuery += " +(@\\{http\\://www.alfresco.org/model/content/1.0\\}content.mimetype:application/octet-stream OR"; - luceneQuery += " @\\{http\\://www.alfresco.org/model/content/1.0\\}content.mimetype:text/html)" - - - // include all published + my drafts - luceneQuery += " +((" + - " -ISNOTNULL:\"{http://www.alfresco.org/model/content/1.0}published\" " + - " +@cm\\:creator:\"" + person.properties.userName + "\"" + - ") OR (" + - " +ISNOTNULL:\"{http://www.alfresco.org/model/content/1.0}published\" " + - ")) "; - - // date query ? - if (fromDate != null || toDate != null) - { - luceneQuery += getCreationDateRangeQuery(fromDate, toDate); - } - - // is a tag selected? - if (tag != null) - { - luceneQuery += " +PATH:\"/cm:taggable/cm:" + search.ISO9075Encode(tag) + "/member\" "; - } - - var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}published"; - - // get the data - return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getBlogPostData); -} - -function main() -{ - // get requested node - var node = getRequestNode(); - if (status.getCode() != status.STATUS_OK) - { - return; - } - - // process additional parameters - var index = args["startIndex"] != undefined ? parseInt(args["startIndex"]) : 0; - var count = args["pageSize"] != undefined ? parseInt(args["pageSize"]) : 10; - - // begin and end date - var fromDate = null; - if (args["fromDate"] != undefined) - { - var tmp = parseInt(args["fromDate"]); - if (tmp != Number.NaN) - { - fromDate = new Date(tmp); - } - } - var toDate = null; - if (args["toDate"] != undefined) - { - var tmp = parseInt(args["toDate"]); - if (tmp != Number.NaN) - { - toDate = new Date(tmp); - } - } - - // selected tag - var tag = (args["tag"] != undefined && args["tag"].length > 0) ? args["tag"] : null; - - // fetch and assign the data - model.data = getBlogPostList(node, fromDate, toDate, tag, index, count); - - // fetch the contentLength param - var contentLength = args["contentLength"] != undefined ? parseInt(args["contentLength"]) : -1; - model.contentLength = isNaN(contentLength) ? -1 : contentLength; - - // assign the blog node - model.blog = node; - model.externalBlogConfig = hasExternalBlogConfiguration(node); -} - -main(); diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts.post.json.js b/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts.post.json.js deleted file mode 100644 index fba57a7a7b..0000000000 --- a/config/alfresco/templates/webscripts/org/alfresco/repository/blogs/posts/blog-posts.post.json.js +++ /dev/null @@ -1,101 +0,0 @@ - - - - -function ensureTagScope(node) -{ - if (! node.isTagScope) - { - node.isTagScope = true; - } - - // also check the parent (the site!) - if (! node.parent.isTagScope) - { - node.parent.isTagScope = true; - } -} - -/** - * Creates a blog post - */ -function createBlogPost(blogNode) -{ - // fetch the data required to create the post - var title = ""; - if (json.has("title")) - { - title = json.get("title"); - } - var content = ""; - if (json.has("content")) - { - content = json.get("content"); - } - var tags = []; - if (json.has("tags")) - { - // get the tags JSONArray and copy it into a real javascript array object - var tmp = json.get("tags"); - for (var x=0; x < tmp.length(); x++) - { - tags.push(tmp.get(x)); - } - } - - // get a unique name - var nodeName = getUniqueChildName(blogNode, "post"); - - // we simply create a new file inside the blog folder - var postNode = blogNode.createNode(nodeName, "cm:content"); - - // set values where supplied - postNode.properties.title = title; - postNode.mimetype = "text/html"; - postNode.content = content; - postNode.tags = tags; - postNode.save(); - - // check whether it is in draft mode - var isDraft = json.has("draft") && json.get("draft").toString() == "true"; - if (isDraft) - { - // disable permission inheritance. The result is that only - // the creator will have access to the draft - postNode.setInheritsPermissions(false); - } - else - { - setOrUpdateReleasedAndUpdatedDates(postNode); - } - - return postNode; -} - -function main() -{ - // get requested node - var node = getRequestNode(); - if (status.getCode() != status.STATUS_OK) - { - return; - } - - ensureTagScope(node); - - var post = createBlogPost(node); - model.item = getBlogPostData(post); - model.externalBlogConfig = hasExternalBlogConfiguration(node); - - if (json.has("site") && json.has("container") && json.has("page") && !model.item.isDraft) - { - var data = - { - title: model.item.node.properties.title, - page: json.get("page") + "?postId=" + model.item.node.properties.name - }; - activities.postActivity("org.alfresco.blog.post-created", json.get("site"), "blog", jsonUtils.toJSONString(data)); - } -} - -main(); diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 4167448b0b..56932058fe 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -1018,6 +1018,13 @@ parent="baseArchivedNodeWebScript"> + + + + + + + diff --git a/source/java/org/alfresco/repo/web/scripts/WebScriptTestSuite.java b/source/java/org/alfresco/repo/web/scripts/WebScriptTestSuite.java index 49e5d79240..c0f1b2b902 100644 --- a/source/java/org/alfresco/repo/web/scripts/WebScriptTestSuite.java +++ b/source/java/org/alfresco/repo/web/scripts/WebScriptTestSuite.java @@ -25,7 +25,7 @@ import org.alfresco.repo.web.scripts.action.RunningActionRestApiTest; import org.alfresco.repo.web.scripts.activities.feed.control.FeedControlTest; import org.alfresco.repo.web.scripts.admin.AdminWebScriptTest; import org.alfresco.repo.web.scripts.audit.AuditWebScriptTest; -import org.alfresco.repo.web.scripts.blog.BlogServiceTest; +import org.alfresco.repo.web.scripts.blogs.BlogServiceTest; import org.alfresco.repo.web.scripts.dictionary.DictionaryRestApiTest; import org.alfresco.repo.web.scripts.discussion.DiscussionServiceTest; import org.alfresco.repo.web.scripts.forms.FormRestApiGet_Test; diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/AbstractBlogWebScript.java b/source/java/org/alfresco/repo/web/scripts/blogs/AbstractBlogWebScript.java new file mode 100644 index 0000000000..025af42a08 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/AbstractBlogWebScript.java @@ -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 . + */ +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; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/AllBlogTests.java b/source/java/org/alfresco/repo/web/scripts/blogs/AllBlogTests.java new file mode 100644 index 0000000000..c71aa8ebc5 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/AllBlogTests.java @@ -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 . + */ +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 +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/BlogLibJs.java b/source/java/org/alfresco/repo/web/scripts/blogs/BlogLibJs.java new file mode 100644 index 0000000000..b3241bfcb1 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/BlogLibJs.java @@ -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 . + */ +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 getBlogPropertiesArray(JSONObject json) + { + Map arr = new HashMap(); + + 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 arr, String jsonKey, QName mapKey) + { + try + { + if (json.has(jsonKey)) + { + arr.put(mapKey, json.getString(jsonKey)); + } + } catch (JSONException ignored) + { + // Intentionally empty + } + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/BlogPostLibJs.java b/source/java/org/alfresco/repo/web/scripts/blogs/BlogPostLibJs.java new file mode 100644 index 0000000000..5e691a47cb --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/BlogPostLibJs.java @@ -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 . + */ +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 getBlogPostData(NodeRef node, ServiceRegistry services) + { + Map data = new HashMap(); + 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; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blog/BlogServiceTest.java b/source/java/org/alfresco/repo/web/scripts/blogs/BlogServiceTest.java similarity index 77% rename from source/java/org/alfresco/repo/web/scripts/blog/BlogServiceTest.java rename to source/java/org/alfresco/repo/web/scripts/blogs/BlogServiceTest.java index 953b08c2fa..7d1a4d4bb1 100644 --- a/source/java/org/alfresco/repo/web/scripts/blog/BlogServiceTest.java +++ b/source/java/org/alfresco/repo/web/scripts/blogs/BlogServiceTest.java @@ -16,9 +16,10 @@ * 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.blog; +package org.alfresco.repo.web.scripts.blogs; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -27,21 +28,23 @@ 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; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.json.JSONArray; -import org.json.JSONObject; /** * Unit Test to test Blog Web Script API @@ -65,7 +68,12 @@ public class BlogServiceTest extends BaseWebScriptTest 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 posts = new ArrayList(5); private List drafts = new ArrayList(5); @@ -279,19 +287,84 @@ public class BlogServiceTest extends BaseWebScriptTest 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); + 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 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 @@ -300,6 +373,7 @@ public class BlogServiceTest extends BaseWebScriptTest 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")); @@ -310,6 +384,17 @@ public class BlogServiceTest extends BaseWebScriptTest 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 @@ -401,7 +486,7 @@ public class BlogServiceTest extends BaseWebScriptTest assertEquals(this.posts.size(), result.getInt("total")); } - public void _testGetDrafts() throws Exception + public void testGetDrafts() throws Exception { String url = URL_BLOG_POSTS + "/mydrafts"; Response response = sendRequest(new GetRequest(URL_BLOG_POSTS), 200); @@ -419,7 +504,7 @@ public class BlogServiceTest extends BaseWebScriptTest } - public void _testMyPublished() throws Exception + public void testMyPublished() throws Exception { String url = URL_BLOG_POSTS + "/mypublished"; Response response = sendRequest(new GetRequest(url), 200); @@ -501,8 +586,8 @@ public class BlogServiceTest extends BaseWebScriptTest try { for (int y=0; y < 3; y++) { - _testPostTags(); - _testClearTags(); + off_testPostTags(); + off_testClearTags(); } System.err.println("------------- SUCCEEDED ---------------"); @@ -540,7 +625,7 @@ public class BlogServiceTest extends BaseWebScriptTest } } - public void _testPostTags() throws Exception + public void off_testPostTags() throws Exception { String[] tags = { "first", "test" }; JSONObject item = createPost("tagtest", "tagtest", tags, false, 200); @@ -555,7 +640,7 @@ public class BlogServiceTest extends BaseWebScriptTest assertEquals("second", item.getJSONArray("tags").get(2)); } - public void _testClearTags() throws Exception + public void off_testClearTags() throws Exception { String[] tags = { "abc", "def"}; JSONObject item = createPost("tagtest", "tagtest", tags, false, 200); diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/CommentsLibJs.java b/source/java/org/alfresco/repo/web/scripts/blogs/CommentsLibJs.java new file mode 100644 index 0000000000..c599961a18 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/CommentsLibJs.java @@ -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 . + */ +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 getComments(NodeRef node, ServiceRegistry services) + { + List result = new ArrayList(); + + NodeRef commentsFolder = getCommentsFolder(node, services); + if (commentsFolder != null) + { + List 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 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 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; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/RequestUtilsLibJs.java b/source/java/org/alfresco/repo/web/scripts/blogs/RequestUtilsLibJs.java new file mode 100644 index 0000000000..7287f6e342 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/RequestUtilsLibJs.java @@ -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 . + */ +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: + * + *
+     * /api/blog/site/{site}/{container}/{path}/posts
+     * /api/blog/site/{site}/{container}/posts
+     * /api/blog/node/{store_type}/{store_id}/{id}/posts
+     * 
+ */ + public static NodeRef getRequestNode(WebScriptRequest req, ServiceRegistry services) + { + NodeRef result = null; + + Map 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 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 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; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/blog/BlogGet.java b/source/java/org/alfresco/repo/web/scripts/blogs/blog/BlogGet.java new file mode 100644 index 0000000000..eb69cf8b12 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/blog/BlogGet.java @@ -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 . + */ +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 executeImpl(WebScriptRequest req, Status status, Cache cache) + { + Map model = new HashMap(); + + // get requested node + NodeRef node = RequestUtilsLibJs.getRequestNode(req, services); + model.put(ITEM, node); + + return model; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/blog/BlogPut.java b/source/java/org/alfresco/repo/web/scripts/blogs/blog/BlogPut.java new file mode 100644 index 0000000000..992cf1457a --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/blog/BlogPut.java @@ -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 . + */ +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 executeImpl(WebScriptRequest req, Status status, Cache cache) + { + Map model = new HashMap(); + + // 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 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); + } + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/post/BlogPostDelete.java b/source/java/org/alfresco/repo/web/scripts/blogs/post/BlogPostDelete.java new file mode 100644 index 0000000000..798488d71b --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/post/BlogPostDelete.java @@ -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 . + */ +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 executeImpl(WebScriptRequest req, Status status, Cache cache) + { + Map model = new HashMap(); + + // get requested node + NodeRef node = RequestUtilsLibJs.getRequestNode(req, services); + + // Map 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); + } + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/post/BlogPostGet.java b/source/java/org/alfresco/repo/web/scripts/blogs/post/BlogPostGet.java new file mode 100644 index 0000000000..d038b241e8 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/post/BlogPostGet.java @@ -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 . + */ +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 executeImpl(WebScriptRequest req, Status status, Cache cache) + { + Map model = new HashMap(); + + // get requested node + NodeRef node = RequestUtilsLibJs.getRequestNode(req, services); + Map 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; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/posts/AbstractGetBlogWebScript.java b/source/java/org/alfresco/repo/web/scripts/blogs/posts/AbstractGetBlogWebScript.java new file mode 100644 index 0000000000..3f44f809dc --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/posts/AbstractGetBlogWebScript.java @@ -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 . + */ +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 executeImpl(WebScriptRequest req, Status status, Cache cache) + { + Map model = new HashMap(); + + // get requested node + NodeRef node = RequestUtilsLibJs.getRequestNode(req, services); + + // process additional parameters. + 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 blogPostList = getBlogPostList(node, fromDate, toDate, + tag, pagingReq); + + createFtlModel(req, model, node, pagingReq, blogPostList); + + return model; + } + + protected void createFtlModel(WebScriptRequest req, Map model, NodeRef node, PagingRequest pagingReq, + PagingResults blogPostList) + { + Map blogPostsData = new HashMap(); + + final Pair 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> blogPostDataSets = new ArrayList>(blogPostList.getPage().size()); + for (BlogPostInfo postInfo : blogPostList.getPage()) + { + Map 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 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 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 getBlogPostList(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq) + { + PagingResults results = getBlogResultsImpl(node, fromDate, toDate, tag, pagingReq); + return results; + } + + protected abstract PagingResults getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq); +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsGet.java b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsGet.java new file mode 100644 index 0000000000..30ab5147fd --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsGet.java @@ -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 . + */ +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 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); + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsMyDraftsGet.java b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsMyDraftsGet.java new file mode 100644 index 0000000000..ca985db7f4 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsMyDraftsGet.java @@ -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 . + */ +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 getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq) + { + return blogService.getDrafts(node, AuthenticationUtil.getFullyAuthenticatedUser(), pagingReq); + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsMyPublishedGet.java b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsMyPublishedGet.java new file mode 100644 index 0000000000..113d3ef8cd --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsMyPublishedGet.java @@ -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 . + */ +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 getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq) + { + String fullyAuthenticatedUser = AuthenticationUtil.getFullyAuthenticatedUser(); + return blogService.getPublished(node, fromDate, toDate, fullyAuthenticatedUser, pagingReq); + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsNewGet.java b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsNewGet.java new file mode 100644 index 0000000000..2796a49d07 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsNewGet.java @@ -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 . + */ +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 getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq) + { + return blogService.getPublished(node, fromDate, toDate, null, pagingReq); + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsPerMonthGet.java b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsPerMonthGet.java new file mode 100644 index 0000000000..aebb0554be --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsPerMonthGet.java @@ -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 . + */ +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 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 model, NodeRef node, PagingRequest pagingReq, PagingResults 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 getMonthDataObject(Date date) + { + Map data = new HashMap(); + 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> getBlogPostMonths(PagingResults nodes) + { + // will hold the months information + List> data = new ArrayList>(); + + // do we have posts? + if (!nodes.getPage().isEmpty()) + { + int currYear = -1; + int currMonth = -1; + Map 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 emptyData = getMonthDataObject(new Date()); + emptyData.put("count", 0); + data.add(emptyData); + } + + return data; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsPost.java b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsPost.java new file mode 100644 index 0000000000..5330a28060 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsPost.java @@ -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 . + */ +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 executeImpl(WebScriptRequest req, Status status, Cache cache) + { + Map model = new HashMap(); + + JsonParams jsonPostParams = parsePostParams(req); + + NodeRef node = RequestUtilsLibJs.getRequestNode(req, services); + ensureTagScope(node); + + NodeRef post = createBlogPost(jsonPostParams, node); + + Map 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 tags = new ArrayList(); + 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 tagsParam = new ArrayList(); + if (jsonParams.getTags() != null) + { + tagsParam.addAll(jsonParams.getTags()); + } + + ChildAssociationRef newPostNode = blogService.createBlogPost(blogNode, titleParam, contentParam, isDraftParam); + + // Ignore empty string tags + List nonEmptyTags = new ArrayList(); + 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 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 getTags() + { + return tags; + } + public void setTags(List 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; + } + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsPublishedExtGet.java b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsPublishedExtGet.java new file mode 100644 index 0000000000..6e588cba7e --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/blogs/posts/BlogPostsPublishedExtGet.java @@ -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 . + */ +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 getBlogResultsImpl(NodeRef node, Date fromDate, Date toDate, String tag, PagingRequest pagingReq) + { + return blogService.getPublishedExternally(node, pagingReq); + } +}