- added paged results lib methods

- cleanup for blogs, comments and discussions API
- deleting a forum reply post now changes the content to "removed" instead of deleting the node
- fix for comment deletion and archive filter in client side javascript

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@9612 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Michael Ru
2008-07-01 13:44:33 +00:00
parent 0c4683657d
commit 310d127f36
32 changed files with 984 additions and 1134 deletions

View File

@@ -1,88 +1,49 @@
/** Name of the blog details aspect. */
const BLOG_DETAILS_ASPECT = "blg:blogDetails";
/**
* Fetches the blog properties from the json object and adds them to the array.
* Fetches the blog properties from the json object and adds them to an array
* using the correct property names as indexes.
*/
function getBlogPropertiesArray()
{
var arr = new Array();
if (json.has("blogType"))
{
arr["blg:blogImplementation"] = json.get("blogType");
}
if (json.has("blogId"))
{
arr["blg:id"] = json.get("blogId");
}
if (json.has("blogName"))
{
arr["blg:name"] = json.get("blogName");
}
if (json.has("blogDescription"))
{
arr["blg:description"] = json.get("blogDescription");
}
if (json.has("blogUrl"))
{
arr["blg:url"] = json.get("blogUrl");
}
if (json.has("username"))
{
arr["blg:userName"] = json.get("username");
}
if (json.has("password"))
{
arr["blg:password"] = json.get("password");
}
return arr;
var arr = new Array();
if (json.has("blogType"))
{
arr["blg:blogImplementation"] = json.get("blogType");
}
if (json.has("blogId"))
{
arr["blg:id"] = json.get("blogId");
}
if (json.has("blogName"))
{
arr["blg:name"] = json.get("blogName");
}
if (json.has("blogDescription"))
{
arr["blg:description"] = json.get("blogDescription");
}
if (json.has("blogUrl"))
{
arr["blg:url"] = json.get("blogUrl");
}
if (json.has("username"))
{
arr["blg:userName"] = json.get("username");
}
if (json.has("password"))
{
arr["blg:password"] = json.get("password");
}
return arr;
}
/**
* Returns the data of a blog post.
* Returns the data object of a blog node.
*/
function getBlogData(node)
{
return node;
}
/**
* Returns an array containing all topics found in the passed array.
* Filters out non-fm:topic nodes.
*/
function getBlogListData(nodes, index, count)
{
var items = new Array();
var i;
var added = 0;
for (i = index; i < nodes.length && added < count; i++)
{
items.push(getBlogData(nodes[i]));
added++;
}
return ({
"total" : nodes.length,
"pageSize" : count,
"startIndex" : index,
"itemCount" : items.length,
"items": items
});
}
/**
* Returns a list of topics, as returned by the lucene query
*/
function getBlogsListByLuceneQuery(node, luceneQuery, sortAttribute, ascending, index, count)
{
var nodes = null;
if (sortAttribute != null)
{
nodes = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, ascending);
}
else
{
nodes = search.luceneSearch(luceneQuery);
}
return getBlogListData(nodes, index, count);
}

View File

@@ -2,16 +2,14 @@
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
model.item = node;
// process additional parameters
model.item = getBlogData(node);
}
main();

View File

@@ -6,38 +6,38 @@
*/
function updateBlog(node)
{
var arr = getBlogPropertiesArray();
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);
}
// 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();
node.save();
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// update
updateBlog(node);
// update blog
updateBlog(node);
model.item = node;
model.item = getBlogData(node);
}
main();

View File

@@ -1,34 +1,4 @@
const DRAFT_FOLDER_NAME = "Drafts";
/**
* Returns the draft folder.
*/
function getOrCreateDraftsFolder(node)
{
var draftFolder = node.childByNamePath(DRAFT_FOLDER_NAME);
if (draftFolder == null)
{
draftFolder = node.createNode(DRAFT_FOLDER_NAME, "cm:folder");
}
return draftFolder;
}
function getCommentsCount(node)
{
// check whether there are comments
// PENDING: this should use the comments API
if (node.hasAspect("fm:discussable"))
{
var forumNode = node.childAssocs["fm:discussion"][0];
var topicNode = forumNode.childAssocs["cm:contains"][0];
return topicNode.childAssocs["cm:contains"].length
}
else
{
return 0;
}
}
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/comments/comments.lib.js">
/**
* Returns the data of a blog post.
@@ -48,69 +18,19 @@ function getBlogPostData(node)
// outOfDate
if ((node.properties["blg:lastUpdate"] != undefined))
{
if ((node.properties["cm:modified"] - node.properties["blg:lastUpdate"]) > 5000)
{
data.outOfDate = true;
}
else
{
data.outOfDate = false;
}
if ((node.properties["cm:modified"] - node.properties["blg:lastUpdate"]) > 5000)
{
data.outOfDate = true;
}
else
{
data.outOfDate = false;
}
}
else
{
data.outOfDate = false;
data.outOfDate = false;
}
return data;
}
/**
* Returns the data of a blog post.
*/
/*function getBlogPostData(node)
{
return node;
}*/
/**
* Returns an array containing all topics found in the passed array.
* Filters out non-fm:topic nodes.
*/
function getBlogPostListData(nodes, index, count)
{
var items = new Array();
var i;
var added = 0;
for (i = index; i < nodes.length && added < count; i++)
{
items.push(getBlogPostData(nodes[i]));
added++;
}
return ({
"total" : nodes.length,
"pageSize" : count,
"startIndex" : index,
"itemCount" : items.length,
"items": items
});
}
/**
* Returns a list of topics, as returned by the lucene query
*/
function getBlogPostListByLuceneQuery(node, luceneQuery, sortAttribute, ascending, index, count)
{
var nodes = null;
if (sortAttribute != null)
{
nodes = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, ascending);
}
else
{
nodes = search.luceneSearch(luceneQuery);
}
return getBlogPostListData(nodes, index, count);
}

View File

@@ -1,65 +1,84 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/requestutils.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/blogs/blogpost.lib.js">
var POST_ACTION = "publish";
var UPDATE_ACTION = "update";
var REMOVE_ACTION = "unpublish";
const POST_ACTION = "publish";
const UPDATE_ACTION = "update";
const REMOVE_ACTION = "unpublish";
function executeAction(node, action)
/**
* Validates the action to execute.
* @return the action name to be used for the blog-post action or null if the specified action is invalid
*/
function validateAction(node, action)
{
var blogAction = "";
var blogAction = null;
var isPublished = false;
if ((node.hasAspect("blg:blogPost")) && (node.properties["blg:published"] == true))
{
isPublished = true;
}
// make sure we have a real JavaScript object,
// otherwise switch won't work correctly
// make sure we have a real JavaScript object, otherwise switch won't work correctly
action = "" + action;
switch (action)
{
case POST_ACTION:
blogAction = (isPublished ? "" : "post");
break;
case UPDATE_ACTION:
blogAction = (isPublished ? "update" : "");
break;
case REMOVE_ACTION:
blogAction = (isPublished ? "remove" : "");
break;
case POST_ACTION:
blogAction = (isPublished ? "" : "post");
break;
case UPDATE_ACTION:
blogAction = (isPublished ? "update" : "");
break;
case REMOVE_ACTION:
blogAction = (isPublished ? "remove" : "");
break;
}
if (blogAction != "")
if (blogAction === null)
{
// set an error status
status.setCode(status.STATUS_BAD_REQUEST, "Invalid action specified (node in wrong state?)");
return null;
}
else
{
return blogAction;
}
}
/**
* Publishe, update or removes the blog from/to the external blog
*/
function executeAction(node, action)
{
// get the blog action to call (the names differ from the constants defined above)
var blogAction = validateAction(node, action);
if (blogAction != null)
{
var blog = actions.create("blog-post");
blog.parameters.action = blogAction;
blog.execute(node);
result = blog.parameters["result"];
logger.log("Blog action result: " + result);
model.message = result;
/* Check whether action succeeded
if (result != "sfsdf")
{
}*/
}
// PENDING: how do we know that the action succeeded?
model.result = blog.parameters["result"];
logger.log("Blog action result: " + result);
}
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// fetch and execute the action
var action = json.get("action");
executeAction(node, action);
model.item = getBlogPostData(node);
// fetch and execute the action
var action = json.get("action");
executeAction(node, action);
// get the updated data for the blog post
model.item = getBlogPostData(node);
}
main();

View File

@@ -1,33 +1,31 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/requestutils.lib.js">
/**
* Deletes a topic node.
* Deletes a blog post node.
*/
function deletePost(postNode)
function deleteBlogPost(postNode)
{
// we simply delete the topic
var qnamePath = postNode.qnamePath;
logger.log("Deleting node " + qnamePath);
var isDeleted = postNode.remove();
logger.log("Node deleted: " + isDeleted);
if (! isDeleted)
{
status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "Unable to delete node: " + qnamePath);
return;
}
model.message = "Node " + qnamePath + " deleted";
// 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;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
deletePost(node);
deleteBlogPost(node);
}
main();

View File

@@ -3,19 +3,16 @@
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// PENDING: type check?
// assign data
model.item = getBlogPostData(node);
model.contentFormat = (args["contentFormat"] != undefined) ? args["contentFormat"] : "full";
// assign data
model.item = getBlogPostData(node);
model.contentFormat = (args["contentFormat"] != undefined) ? args["contentFormat"] : "full";
}
main();

View File

@@ -2,39 +2,30 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/blogs/blogpost.lib.js">
/**
* Creates a post inside the passed forum node.
* Updates a blog post node
*/
function updatePost(postNode)
function updateBlogPost(postNode)
{
/*var name = "";
if (json.has("name"))
{
title = json.get("name");
}*/
var title = "";
if (json.has("title"))
{
title = json.get("title");
}
var content = json.get("content");
// fetch the new data
var title = "";
if (json.has("title"))
{
title = json.get("title");
}
var content = json.get("content");
// update the topic title
postNode.properties.title = title;
postNode.mimetype = "text/html";
postNode.content = content;
postNode.save();
// update the node
postNode.properties.title = title;
postNode.mimetype = "text/html";
postNode.content = content;
postNode.save();
// PENDING:
// check whether it is draft mode
/*if (postNode.hasAspect("cm:workingcopy") && json.get("draft") == "false")
{
postNode.removeAspect("cm:workingcopy");
}*/
// try to change the file name
/*if (name.length > 0)
{
postNode.name = name;
}*/
}
function main()
@@ -46,8 +37,8 @@ function main()
return;
}
// update
updatePost(node);
// update blog post
updateBlogPost(node);
model.item = getBlogPostData(node);
}

View File

@@ -1,91 +1,103 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/requestutils.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/blogs/blogpost.lib.js">
/**
* 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);
}
function getEndOfMonthDate(date)
{
var year = date.getFullYear();
var month = date.getMonth();
var beginOfNextMonth = new Date(year, month + 1, 1); // will increment year by 1 if month > 11
return new Date(beginOfNextMonth.getTime() - 1);
return new Date(date.getFullYear(), date.getMonth(), 1);
}
/**
* Creates an object containing information about the month.
* This object holds all the data returned.
* 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.beginOfMonthMillis = data.beginOfMonth.getTime();
data.endOfMonth = getEndOfMonthDate(date);
data.endOfMonthMillis = data.endOfMonth.getTime();
data.count = 1;
return data;
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 all posts found in the forum.
* 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 + "/*\" ";
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created";
nodes = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, true);
// fetch all dates with different month and year. Throw away doubles.
var data = new Array();
if (nodes.length > 0) {
var curr = nodes[0].properties["cm:created"];
var currData = getMonthDataObject(curr);
data.push(currData);
for (var x=1; x < nodes.length; x++)
{
var date = nodes[x].properties["cm:created"];
// check whether we are in a new month
if (curr.getFullYear() != date.getFullYear() || curr.getMonth() != date.getMonth())
{
curr = node;
currData = getMonthDataObject(curr);
data.push(currData);
}
// or still the same one
else
{
currData.count += 1;
}
}
}
return data;
// query information
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" +
" +PATH:\"" + node.qnamePath + "/*\" ";
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created";
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:created"];
// 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;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// fetch the months
model.data = getBlogPostMonths(node);
// fetch the months
model.data = getBlogPostMonths(node);
}
main();

View File

@@ -1,63 +1,64 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/requestutils.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/searchutils.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/generic-paged-results.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/blogs/blogpost.lib.js">
/**
* Fetches all posts found in the forum.
* Fetches all posts of the given blog
*/
function getBlogPostList(node, fromDate, toDate, index, count)
{
// query information
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" +
" +PATH:\"" + node.qnamePath + "/*\" ";
// date query ?
if (fromDate != null || toDate != null)
{
luceneQuery += getCreationDateRangeQuery(fromDate, toDate);
}
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created";
// get the data
return getBlogPostListByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count);
// query information
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" +
" +PATH:\"" + node.qnamePath + "/*\" ";
// date query ?
if (fromDate != null || toDate != null)
{
luceneQuery += getCreationDateRangeQuery(fromDate, toDate);
}
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;
}
// 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;
// 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);
}
}
model.data = getBlogPostList(node, fromDate, toDate, index, count);
model.contentFormat = (args["contentFormat"] != undefined) ? args["contentFormat"] : "full";
// 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);
}
}
// fetch and assign the data
model.data = getBlogPostList(node, fromDate, toDate, index, count);
model.contentFormat = (args["contentFormat"] != undefined) ? args["contentFormat"] : "full";
}
main();

View File

@@ -3,14 +3,13 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/blogs/blogpost.lib.js">
/**
* Creates a post inside the passed forum node.
* Creates a blog post
*/
function createBlogPost(blogNode)
{
// fetch the data required to create a topic
// fetch the data required to create the post
var title = json.get("title");
var content = json.get("content");
logger.log("Creating new blog post " + title + " with text " + content);
// get a unique name
var name = getUniqueChildName(blogNode, "post");

View File

@@ -2,37 +2,32 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/comments/comments.lib.js">
/**
* Deletes a topic node.
* Delete a comment.
*/
function deleteComment(node)
{
// we simply delete the topic
var qnamePath = node.qnamePath;
logger.log("Deleting node " + qnamePath);
var isDeleted = node.remove();
logger.log("Node deleted: " + isDeleted);
if (! isDeleted)
{
status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "Unable to delete node: " + qnamePath);
return;
}
// also remove the discussable aspect if there are no more comments
deleteCommentsFolder(node);
model.message = "Node " + qnamePath + " deleted";
// we simply delete the topic
var nodeRef = node.nodeRef;
var isDeleted = node.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;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
deleteComment(node);
deleteComment(node);
}
main();

View File

@@ -3,16 +3,14 @@
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
model.item = node;
// process additional parameters
model.item = getCommentData(node);
}
main();

View File

@@ -2,37 +2,37 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/comments/comments.lib.js">
/**
* Creates a post inside the passed forum node.
* Update a comment
*/
function updateComment(node)
{
/*var title = "";
if (json.has("title"))
{
title = json.get("title");
}*/
var content = json.get("content");
// update the topic title
//postNode.properties.title = title;
node.mimetype = "text/html";
node.content = content;
node.save();
var title = "";
if (json.has("title"))
{
title = json.get("title");
}
var content = json.get("content");
// update the topic title
node.properties.title = title;
node.mimetype = "text/html";
node.content = content;
node.save();
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// update
updateComment(node);
model.item = node;
// update comment
updateComment(node);
model.item = getCommentData(node);
}
main();

View File

@@ -1,39 +1,31 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/requestutils.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/generic-paged-results.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/comments/comments.lib.js">
/**
* Fetches all posts found in the forum.
* Get all comments for a node
*/
function getCommentsList(node, index, count)
{
var nodes = new Array();
// comments are added through a custom child association ("cm:comments") that links to a cm:folder that holds all the comment files
var commentFolder = getCommentsFolder(node);
if (commentFolder != null)
{
nodes = commentFolder.childAssocs["cm:contains"];
}
var nodes = getComments(node);
return getCommentListData(nodes, index, count);
return getPagedResultsData(nodes, index, count, getCommentData);
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// 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;
// process additional parameters
var index = args["startIndex"] != undefined ? parseInt(args["startIndex"]) : 0;
var count = args["pageSize"] != undefined ? parseInt(args["pageSize"]) : 10;
model.data = getCommentsList(node, index, count);
model.data = getCommentsList(node, index, count);
}
main();

View File

@@ -1,23 +1,44 @@
/** Name used for the topic that contains all comments. */
const COMMENTS_TOPIC_NAME = "Comments";
/**
* Returns all comment nodes for a given node.
* @return an array of comments.
*/
function getComments(node)
{
var commentsFolder = getCommentsFolder(node);
if (commentsFolder != null)
{
var elems = commentsFolder.childAssocs["cm:contains"];
if (elems != null)
{
return elems;
}
}
// no comments found, return an empty array
return new Array();
}
/**
* Returns the folder that contains all the comments.
* We currently use the forum model for testing purpose
* PENDING: use a proper model!
*/
*
* We currently use the fm:discussable aspect where we
* add a "Comments" topic to it.
*/
function getCommentsFolder(node)
{
if (node.hasAspect("fm:discussable"))
{
var forumFolder = node.childAssocs["fm:discussion"][0];
// we simply take the first topic folder in it
// PENDING: this is error prone!
var topicFolder = forumFolder.childAssocs["cm:contains"][0];
return topicFolder;
}
else
{
return null;
}
if (node.hasAspect("fm:discussable"))
{
var forumFolder = node.childAssocs["fm:discussion"][0];
var topicFolder = forumFolder.childByNamePath(COMMENTS_TOPIC_NAME);
return topicFolder;
}
else
{
return null;
}
}
/**
@@ -25,75 +46,31 @@ function getCommentsFolder(node)
*/
function getOrCreateCommentsFolder(node)
{
var commentsFolder = getCommentsFolder(node);
if (commentsFolder != null)
{
return commentsFolder;
}
node.addAspect("fm:discussable");
var forumNode = node.createNode("Comments Forum", "fm:forum", "fm:discussion");
commentsFolder = forumNode.createNode("Comments", "fm:topic", "cm:contains");
return commentsFolder;
var commentsFolder = getCommentsFolder(node);
if (commentsFolder != null)
{
return commentsFolder;
}
// add the aspect and create the forum as well as the comments topic
node.addAspect("fm:discussable");
var forumNode = node.createNode("Forum", "fm:forum", "fm:discussion");
commentsFolder = forumNode.createNode(COMMENTS_TOPIC_NAME, "fm:topic", "cm:contains");
return commentsFolder;
}
/**
* Deletes the comments folder for a node if there are no comments in it.
* Returns the data object for a comment node
*/
function deleteCommentsFolder(node)
{
var commentsFolder = getCommentFolder(node);
if (commentsFolder != null && commentsFolder.childAssocs["cm:contains"] == 0)
{
var forumFolder = node.childAssocs["fm:discussion"][0];
node.removeNode(forumNode);
node.removeAspect("fm:discussable");
}
}
function getCommentData(node)
{
return node;
return node;
}
/**
* Returns an array containing all topics found in the passed array.
* Filters out non-fm:topic nodes.
* Returns the count of comments for a node.
*/
function getCommentListData(nodes, index, count)
function getCommentsCount(node)
{
var items = new Array();
var i;
var added = 0;
for (i = index; i < nodes.length && added < count; i++)
{
items.push(getCommentData(nodes[i]));
added++;
}
return ({
"total" : nodes.length,
"pageSize" : count,
"startIndex" : index,
"itemCount" : items.length,
"items": items
});
return getComments(node).length;
}
/**
* Returns a list of topics, as returned by the lucene query
*/
/*function getBlogsListByLuceneQuery(node, luceneQuery, sortAttribute, ascending, index, count)
{
var nodes = null;
if (sortAttribute != null)
{
nodes = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, ascending);
}
else
{
nodes = search.luceneSearch(luceneQuery);
}
return getBlogListData(nodes, index, count);
}*/

View File

@@ -7,37 +7,41 @@
*/
function addComment(node)
{
// fetch the data required to create a comment
//var title = json.get("title");
var content = json.get("content");
logger.log("Creating new comment with text " + content);
// fetch the data required to create a comment
var title = "";
if (json.has("title"))
{
title = json.get("title");
}
var content = json.get("content");
var commentsFolder = getOrCreateCommentsFolder(node);
// fetch the parent to add the node to
var commentsFolder = getOrCreateCommentsFolder(node);
// get a unique name
var name = getUniqueChildName(commentsFolder, "comment");
// we simply create a new file inside the blog folder
var commentNode = commentsFolder.createNode(name, "fm:post");
commentNode.mimetype = "text/html";
//commentNode.properties.title = title;
commentNode.content = content;
commentNode.save();
return commentNode;
// get a unique name
var name = getUniqueChildName(commentsFolder, "comment");
// create the comment
var commentNode = commentsFolder.createNode(name, "fm:post");
commentNode.mimetype = "text/html";
commentNode.properties.title = title;
commentNode.content = content;
commentNode.save();
return commentNode;
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
var comment = addComment(node);
model.item = comment;
var comment = addComment(node);
model.item = getCommentData(comment);
}
main();

View File

@@ -1,88 +1,102 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/requestutils.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/generic-paged-results.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/topicpost.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/forum/forum-posts.lib.js">
/**
* Prepends a number with zeros to make it a 4numgth string
*/
function toFourDigitString(num)
{
if (num < 10) return "000" + num;
if (num < 100) return "00" + num;
if (num < 1000) return "0" + num;
return "" + num;
}
var MAX_NUM_OF_PROCESSED_POSTS = 20;
/**
* Fetches the hot topics found in the forum.
* Hot topics are the one with the most replies recently.
* Hot topics are topics with the most replies over the last x days.
*
* We implement this follows: We fetch all posts in the forum, ordered by inverse
* creation date and fetch the nodes for the first 20 posts
* The current implementation fetches all posts in the forum ordered by inverse
* creation date. It then analyzes the last x posts and fetches the topics thereof,
* keeping track of the number of posts for each.
*
* Note: We only look at topics with replies, the others will therefore not show up
* in that list.
*/
function getHotTopicPostList(node, index, count)
{
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/forum/1.0}post\"" +
" +PATH:\"" + node.qnamePath + "/*/*\"" +
" +ASPECT:\"cm:referencing\"";
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created";
posts = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, false);
// get the posts to check
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/forum/1.0}post\"" +
" +PATH:\"" + node.qnamePath + "/*/*\"" +
" +ASPECT:\"cm:referencing\"";
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created";
var posts = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, false);
/** Implement sort and order logic to show the node with most replies first. */
// PENDING: quick and dirty version, works but needs cleanup!
var max = 20; // only process so many posts
if (posts.length < max) max = posts.length;
var idToNode = new Array();
var idToCount = new Array();
// check how many posts we check in the result set
var max = MAX_NUM_OF_PROCESSED_POSTS;
if (posts.length < max)
{
max = posts.length;
}
// get for each the topic, keeping track of the number of replies and the first occurance
// of the post.
var idToData = {};
for (var x=0; x < max; x++)
{
// get the topic node (which is the direct parent of the post)
var parent = posts[x].parent;
var id = parent.nodeRef.id;
if (idToData[id] != null) {
idToData[id].count += 1;
} else {
idToData[id] = { count: 1, pos: x, node: parent};
}
}
// copy the elements to an array as we will have to sort it
// afterwards
var dataArr = new Array();
for (n in idToData)
{
dataArr.push(idToData[n]);
}
// sort the elements by number of replies, then by the position
var sorter = function(a, b)
{
if (a.count != b.count)
{
// more replies first
return b.count - a.count
}
else {
// lower pos first
return a.pos - b.pos;
}
}
dataArr.sort(sorter);
for (var x=0; x < max; x++)
{
var parent = posts[x].parent;
var id = parent.nodeRef.id;
if (idToCount[id] != null) {
idToCount[id] = idToCount[id] + 1;
} else {
idToNode[id] = parent;
idToCount[id] = 1;
}
}
// get the list sorted by number of replies
var tmp = new Array();
for (var id in idToCount) {
tmp.push(toFourDigitString(idToCount[id]) + id);
}
tmp.sort();
tmp.reverse();
var nodes = Array();
for (var x=0; x < tmp.length; x++)
{
nodes.push(idToNode[tmp[x].substring(4)]);
}
// extract now the nodes
var nodes = Array();
for (var x=0; x < dataArr.length; x++)
{
nodes.push(dataArr[x].node);
}
// get the data
return getTopicPostListData(nodes, index, count);
// get the paginated data
return getPagedResultsData(nodes, index, count, getTopicPostData);
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// 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 the data and assign it to the model
model.data = getHotTopicPostList(node, index, count);
model.contentFormat = (args["contentFormat"] != undefined) ? args["contentFormat"] : "full";
// process additional parameters
var index = args["startIndex"] != undefined ? parseInt(args["startIndex"]) : 0;
var count = args["pageSize"] != undefined ? parseInt(args["pageSize"]) : 10;
// fetch the data and assign it to the model
model.data = getHotTopicPostList(node, index, count);
model.contentFormat = (args["contentFormat"] != undefined) ? args["contentFormat"] : "full";
}
main();

View File

@@ -1,32 +1,17 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/requestutils.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/generic-paged-results.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/topicpost.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/forum/forum-posts.lib.js">
function getLatestAddedPostsListData(nodes, index, count)
function getLatestAddedPostData(node)
{
var items = new Array();
var i;
var added = 0;
for (i = index; i < nodes.length && added < count; i++)
{
// fetch the topic post data and then add the node as reply.
// in case of a new topicpost, the reply and the post will be the
// same, otherwise they differ. The topic post will be used to fetch
// the topic title, while the reply will be used to show the text
var data = getTopicPostData(nodes[i].parent);
data.reply = nodes[i];
items.push(data);
added++;
}
return ({
"total" : nodes.length,
"pageSize" : count,
"startIndex" : index,
"itemCount" : items.length,
"items": items
});
// fetch the topic post data and then add the node as reply.
// in case of a new topic post, the reply and the post will be the
// same, otherwise they differ. The topic post will be used to fetch
// the topic title, while the reply will be used to show the text
var data = getTopicPostData(node.parent);
data.reply = node;
data.isRootPost = data.post.nodeRef == data.reply.nodeRef;
return data;
}
/**
@@ -37,10 +22,9 @@ function getLatestAddedPosts(node, index, count)
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/forum/1.0}post\"" +
" +PATH:\"" + node.qnamePath + "/*/*\"";
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created";
nodes = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, false);
// get the data
return getLatestAddedPostsListData(nodes, index, count);
return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getLatestAddedPostData);
}
function main()
@@ -63,4 +47,3 @@ function main()
}
main();
var x = 0;

View File

@@ -4,6 +4,7 @@
<#macro latestPostJSON item>
{
"topicTitle" : "${item.post.properties.title?js_string}",
"isRootPost" : ${item.isRootPost?string},
<@postLib.postDataJSON refNode=item.topic post=item.reply />
}
</#macro>

View File

@@ -1,11 +1,12 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/requestutils.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/searchutils.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/generic-paged-results.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/topicpost.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/forum/forum-posts.lib.js">
const DEFAULT_NUM_DAYS = 30;
/**
* Returns the date object for the NOW - numdays days in the past
* Returns the date object for the date "numdays" ago
*/
function getTodayMinusXDays(numdays)
{
@@ -17,42 +18,40 @@ function getTodayMinusXDays(numdays)
}
/**
* Fetches all posts found in the forum.
* Fetches all posts added to the forum in the last numdays days
*/
function getTopicPostList(node, numdays, index, count)
{
var fromDate = getTodayMinusXDays(numdays);
// query information
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/forum/1.0}topic\"" +
" +PATH:\"" + node.qnamePath + "/*\" " +
getCreationDateRangeQuery(fromDate, null);
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created";
var fromDate = getTodayMinusXDays(numdays);
// query information
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/forum/1.0}topic\"" +
" +PATH:\"" + node.qnamePath + "/*\" " +
getCreationDateRangeQuery(fromDate, null);
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created";
// get the data
return getTopicPostListByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count);
// get the data
return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getTopicPostData);
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// 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 DEFAULT_NUM_DAYS = 30;
var numdays = args["numdays"] != undefined ? parseInt(args["numdays"]) : DEFAULT_NUM_DAYS;
// fetch the data and assign it to the model
model.data = getTopicPostList(node, numdays, index, count);
model.contentFormat = (args["contentFormat"] != undefined) ? args["contentFormat"] : "full";
// 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 the data and assign it to the model
model.data = getTopicPostList(node, numdays, index, count);
model.contentFormat = (args["contentFormat"] != undefined) ? args["contentFormat"] : "full";
}
main();

View File

@@ -1,37 +1,37 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/requestutils.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/generic-paged-results.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/topicpost.lib.js">
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/forum/forum-posts.lib.js">
/**
* Fetches all posts found in the forum.
*/
function getTopicPostList(node, index, count)
{
// query information
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/forum/1.0}topic\"" +
" +PATH:\"" + node.qnamePath + "/*\" ";
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created";
// get the data
return getTopicPostListByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count);
// query information
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/forum/1.0}topic\"" +
" +PATH:\"" + node.qnamePath + "/*\" ";
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created";
// get the data
return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getTopicPostData);
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// 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;
// process additional parameters
var index = args["startIndex"] != undefined ? parseInt(args["startIndex"]) : 0;
var count = args["pageSize"] != undefined ? parseInt(args["pageSize"]) : 10;
model.data = getTopicPostList(node, index, count);
model.contentFormat = (args["contentFormat"] != undefined) ? args["contentFormat"] : "full";
model.data = getTopicPostList(node, index, count);
model.contentFormat = (args["contentFormat"] != undefined) ? args["contentFormat"] : "full";
}
main();

View File

@@ -1,42 +0,0 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/topicpost.lib.js">
/**
* Returns an array containing all topics found in the passed array.
* Filters out non-fm:topic nodes.
*/
function getTopicPostListData(nodes, index, count)
{
var items = new Array();
var i;
var added = 0;
for (i = index; i < nodes.length && added < count; i++)
{
items.push(getTopicPostData(nodes[i]));
added++;
}
return ({
"total" : nodes.length,
"pageSize" : count,
"startIndex" : index,
"itemCount" : items.length,
"items": items
});
}
/**
* Returns a list of topics, as returned by the lucene query
*/
function getTopicPostListByLuceneQuery(node, luceneQuery, sortAttribute, ascending, index, count)
{
var nodes = null;
if (sortAttribute != null)
{
nodes = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, ascending);
}
else
{
nodes = search.luceneSearch(luceneQuery);
}
return getTopicPostListData(nodes, index, count);
}

View File

@@ -3,17 +3,18 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/topicpost.lib.js">
/**
* Creates a post inside the passed forum node.
* Adds a post to the passed forum node.
*/
function createPost(forumNode)
{
// fetch the data required to create a topic
var title = json.get("title");
var content = json.get("content");
logger.log("Creating New post " + title + " with text " + content);
// create the topic node, and add the first child node representing the topic text
// NOTE: this is a change from the old web client, where the topic title was used as name for the node
// NOTE: this is a change from the old web client, where the topic title was used as name
// for the topic node. We will use generated names to make sure we won't have naming
// clashes.
var name = getUniqueChildName(forumNode, "post");
var topicNode = forumNode.createNode(name, "fm:topic");
@@ -29,15 +30,16 @@ function createPost(forumNode)
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
var topicPost = createPost(node);
model.topicpost = getTopicPostData(topicPost);
var topicPost = createPost(node);
model.topicpost = getTopicPostData(topicPost);
}
main();

View File

@@ -2,89 +2,95 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/topicpost.lib.js">
/**
* Fetches the nodes that are children of post
* Returns all reply nodes to a post
*/
function getRepliesForPost(post)
{
var children = post.sourceAssocs["cm:references"];
if (children === null)
{
return new Array();
}
else
{
return children;
}
var children = post.sourceAssocs["cm:references"];
if (children === null)
{
return new Array();
}
else
{
return children;
}
}
/**
* Fetches the reply node and the child count.
* Fetches the children in addition if levels > 1.
* Returns a data object containing the passed post,
* the number of replies to the post, as well as
* the replies themselves if levels > 1
*/
function getReplyDataRecursive(post, levels)
{
// encapsulates the data: node, childCount, children
var data = new Object();
data.post = post;
var children = getRepliesForPost(post);
data.childCount = children.length;
if (levels > 1)
{
data.children = new Array();
var x = 0;
for (x =0; x < children.length; x++)
{
data.children.push(getReplyDataRecursive(children[x], levels-1));
}
}
return data;
// encapsulates the data: node, childCount, children
var data = new Object();
data.post = post;
var children = getRepliesForPost(post);
data.childCount = children.length;
if (levels > 1)
{
data.children = new Array();
var x = 0;
for (x =0; x < children.length; x++)
{
data.children.push(getReplyDataRecursive(children[x], levels-1));
}
}
return data;
}
/**
* Returns a data object containing all replies of a post.
* @return data object with "children" property that contains an array of reply data objects
*/
function getRepliesImpl(post, levels)
{
var data = getReplyDataRecursive(post, levels + 1);
if (data.children != undefined)
{
return data.children;
}
else
{
return new Array();
}
var data = getReplyDataRecursive(post, levels + 1);
if (data.children != undefined)
{
return data.children;
}
else
{
return new Array();
}
}
function getReplies(node, levels)
{
// we have to differentiate here whether this is a top-level post or a reply
if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
// find the primary post node
var data = getTopicPostData(node); // PENDING: couldn't this be done in a more performant way?
return getRepliesImpl(data.post, levels);
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
return getRepliesImpl(node, levels);
}
else
{
status.setCode(STATUS_BAD_REQUEST, "Incompatible node type. Required either fm:topic or fm:post. Received: " + node.type);
}
// we have to differentiate here whether this is a top-level post or a reply
if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
// find the primary post node.
var data = getTopicPostData(node);
return getRepliesImpl(data.post, levels);
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
// the node is already a post
return getRepliesImpl(node, levels);
}
else
{
status.setCode(STATUS_BAD_REQUEST, "Incompatible node type. Required either fm:topic or fm:post. Received: " + node.type);
}
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// process additional parameters
var levels = args["levels"] != undefined ? parseInt(args["levels"]) : 1;
// process additional parameters
var levels = args["levels"] != undefined ? parseInt(args["levels"]) : 1;
model.data = getReplies(node, levels);
model.data = getReplies(node, levels);
}
main();

View File

@@ -5,69 +5,70 @@
/**
* Creates a post inside the passed forum node.
*/
function createReplyPost(topicNode, parentPostNode)
function createPostReplyImpl(topicNode, parentPostNode)
{
// fetch the data required to create a topic
var title = "";
if (json.has("title"))
{
title = json.get("title");
}
var content = json.get("content");
logger.log("Creating new post with title " + title + " and text " + content);
// fetch the data required to create a topic
var title = "";
if (json.has("title"))
{
title = json.get("title");
}
var content = json.get("content");
// create the topic node, and add the first child node representing the topic text
// NOTE: this is a change from the old web client, where the topic title was used as name for the node
var name = getUniqueChildName(topicNode, "post");
var postNode = topicNode.createNode(name, "fm:post");
postNode.mimetype = "text/html";
postNode.properties.title = title;
postNode.content = content;
postNode.save();
// create the post node using a unique name
var name = getUniqueChildName(topicNode, "post");
var postNode = topicNode.createNode(name, "fm:post");
postNode.mimetype = "text/html";
postNode.properties.title = title;
postNode.content = content;
postNode.save();
// link it to the parent post
postNode.addAspect("cm:referencing");
postNode.createAssociation(parentPostNode, "cm:references");
postNode.save(); // probably not necessary here
// link it to the parent post
postNode.addAspect("cm:referencing");
postNode.createAssociation(parentPostNode, "cm:references");
postNode.save(); // probably not necessary here
return postNode;
return postNode;
}
/**
* Creates a reply to a post.
* @param node The parent post node
*/
function createPostReply(node)
{
// we have to differentiate here whether this is a top-level post or a reply
if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
// find the primary post node
var data = getTopicPostData(node);
var topic = data.topic;
var post = data.post;
return createReplyPost(topic, post);
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
// the forum is the paren of the node
var topic = node.parent;
var post = node;
return createReplyPost(topic, post);
}
else
{
status.setCode(STATUS_BAD_REQUEST, "Incompatible node type. Required either fm:topic or fm:post. Received: " + node.type);
}
// we have to differentiate here whether this is a top-level post or a reply
if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
// find the primary post node
var topic = node;
var post = findPostNode(node);
return createPostReplyImpl(topic, post);
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
// the forum is the parent of the node
var topic = node.parent;
var post = node;
return createPostReplyImpl(topic, post);
}
else
{
status.setCode(STATUS_BAD_REQUEST, "Incompatible node type. Required either fm:topic or fm:post. Received: " + node.type);
return null;
}
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
model.post = createPostReply(node);
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
model.post = createPostReply(node);
}
main();

View File

@@ -1,61 +1,40 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/requestutils.lib.js">
const DELETED_REPLY_POST_MARKER = "[[deleted]]";
/**
* Deletes a topic node.
*/
function deleteTopicPost(topicNode)
{
// we simply delete the topic
var qnamePath = topicNode.qnamePath;
logger.log("Deleting node " + qnamePath);
var isDeleted = topicNode.remove();
logger.log("Node deleted: " + isDeleted);
if (! isDeleted)
{
status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "Unable to delete node: " + qnamePath);
return;
}
model.message = "Node " + qnamePath + " deleted";
// we simply delete the complete topic
var nodeRef = topicNode.nodeRef;
var isDeleted = topicNode.remove();
if (! isDeleted)
{
status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "Unable to delete node: " + nodeRef);
return;
}
model.message = "Node " + nodeRef + " deleted";
}
function addRepliesOfPostRecursive(node, arr)
{
var replies = node.sourceAssocs["cm:references"];
if (replies != null)
{
var x;
for (x = 0; x < replies.length; x++)
{
addRepliesOfPostRecursive(replies[x], arr);
arr.push(replies[x]);
}
}
}
/**
* Deletes a reply post.
* Delete a reply post.
* Note: Because posts are recursive, we can't simply delete the node.
* For now we set a marker text [[delete]] as title and content.
*/
function deleteReplyPost(postNode)
function deleteReplyPost(node)
{
// we have to delete the node as well as all replies
// PENDING: what happens if the user has the right to delete its node
// but not the replies to it?
var nodes = new Array();
addRepliesOfPostRecursive(postNode, nodes);
nodes.push(postNode);
var qnamePath = postNode.qnamePath
var isDeleted = false;
for (x = 0; x < nodes.length; x++)
{
isDeleted = nodes[x].remove();
if (! isDeleted)
{
status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "Unable to delete node: " + nodes[x].nodeRef);
return;
}
}
model.message = "Node " + qnamePath + " deleted";
var title = DELETED_REPLY_POST_MARKER;
var content = DELETED_REPLY_POST_MARKER;
// update the topic title
node.properties.title = title;
node.mimetype = "text/html";
node.content = content;
node.save();
model.message = "Node " + node.nodeRef + " marked as removed";
}
/**
@@ -64,31 +43,31 @@ function deleteReplyPost(postNode)
*/
function deletePost(node)
{
// simple case: topic post
if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
deleteTopicPost(node);
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
deleteReplyPost(node);
}
else
{
status.setCode(status.STATUS_BAD_REQUEST, "Node is not of type fm:topic or fm:post");
}
// simple case: topic post
if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
deleteTopicPost(node);
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
deleteReplyPost(node);
}
else
{
status.setCode(status.STATUS_BAD_REQUEST, "Node is not of type fm:topic or fm:post");
}
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
deletePost(node);
deletePost(node);
}
main();

View File

@@ -6,32 +6,32 @@
*/
function fetchPostData(node)
{
// we have to differentiate here whether this is a top-level post or a reply
// only in the first case we fetch all information (as returned by forum/.../posts)
if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
model.topicpost = getTopicPostData(node);
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
model.post = node;
}
else
{
status.setCode(STATUS_BAD_REQUEST, "Incompatible node type. Required either fm:topic or fm:post. Received: " + node.type);
}
// we have to differentiate here whether this is a top-level post or a reply
// only in the first case we fetch all information (as returned by forum/.../posts)
if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
model.topicpost = getTopicPostData(node);
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
model.post = node;
}
else
{
status.setCode(STATUS_BAD_REQUEST, "Incompatible node type. Required either fm:topic or fm:post. Received: " + node.type);
}
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
fetchPostData(node);
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
fetchPostData(node);
}
main();

View File

@@ -2,107 +2,80 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/discussions/topicpost.lib.js">
/**
* Returns the correct post node to update-
* This function makes sure that a post is returned in case the passed node is a topic.
* Updates the passed forum post node.
*/
function findPostNode(node)
function updatePost(node)
{
if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
return node;
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
var nodes = getOrderedPosts(node);
if (nodes.length > 0)
{
return nodes[0];
}
else
{
status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "First post of topic node" + node.nodeRef + " missing");
}
}
else
{
status.setCode(STATUS_BAD_REQUEST, "Incompatible node type. Required either fm:topic or fm:post. Received: " + node.type);
}
}
/**
* Creates a post inside the passed forum node.
*/
function updatePost(postNode)
{
var title = "";
if (json.has("title"))
{
title = json.get("title");
}
var content = json.get("content");
// update the topic title
postNode.properties.title = title;
postNode.mimetype = "text/html";
postNode.content = content;
postNode.save();
var title = "";
if (json.has("title"))
{
title = json.get("title");
}
var content = json.get("content");
// update the topic title
node.properties.title = title;
node.mimetype = "text/html";
node.content = content;
node.save();
}
function main()
{
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// find the post node - returns the passed node in case node is a post,
// or the primary post in case node is a topic
/* Due to https://issues.alfresco.com/browse/ALFCOM-1775
we will do the search here as we have to reuse the lucene result later
var postNode = findPostNode(node);
if (status.getCode() != status.STATUS_OK)
{
return;
}*/
var postNode = null;
if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
postNode = node;
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
var nodes = getOrderedPosts(node);
if (nodes.length > 0)
{
postNode = nodes[0];
}
else
{
status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "First post of topic node" + node.nodeRef + " missing");
return;
}
}
else
{
status.setCode(STATUS_BAD_REQUEST, "Incompatible node type. Required either fm:topic or fm:post. Received: " + node.type);
return;
}
// update
updatePost(postNode);
// fetch the data to render the result
if (node.nodeRef.equals(postNode.nodeRef)) // false for topic posts
{
model.post = node;
}
else
{
//model.topicpost = getTopicPostData(node);
model.topicpost = getTopicPostDataFromTopicAndPosts(node, nodes);
}
// get requested node
var node = getRequestNode();
if (status.getCode() != status.STATUS_OK)
{
return;
}
// find the post node - returns the passed node in case node is a post,
// or the primary post in case node is a topic
/* Due to https://issues.alfresco.com/browse/ALFCOM-1775
we will do the search here as we have to reuse the lucene result later
var postNode = findPostNode(node);
if (status.getCode() != status.STATUS_OK)
{
return;
}*/
var postNode = null;
if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
postNode = node;
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
var nodes = getOrderedPosts(node);
if (nodes.length > 0)
{
postNode = nodes[0];
}
else
{
status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "First post of topic node" + node.nodeRef + " missing");
return;
}
}
else
{
status.setCode(STATUS_BAD_REQUEST, "Incompatible node type. Required either fm:topic or fm:post. Received: " + node.type);
return;
}
// update
updatePost(postNode);
// fetch the data to render the result
if (node.nodeRef.equals(postNode.nodeRef)) // false for topic posts
{
model.post = node;
}
else
{
// See above, use getTopicPostDataFromTopicAndPosts instead of getTopicPostData
//model.topicpost = getTopicPostData(node);
model.topicpost = getTopicPostDataFromTopicAndPosts(node, nodes);
}
}
main();

View File

@@ -1,12 +1,33 @@
/**
* This library contains functions to work with topics (aka top level posts).
*
* Top-level posts are different from post that act as replies in that
* they have some additional data available:
* lastReplyOn:
* lastReplyFrom:
* totalReplyCount:
* Returns the fm:post node given a fm:topic or fm:post node.
*
* This function makes sure that a post is returned in case the passed node is a topic.
*/
function findPostNode(node)
{
if (node.type == "{http://www.alfresco.org/model/forum/1.0}post")
{
return node;
}
else if (node.type == "{http://www.alfresco.org/model/forum/1.0}topic")
{
var nodes = getOrderedPosts(node);
if (nodes.length > 0)
{
return nodes[0];
}
else
{
status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "First post of topic node" + node.nodeRef + " missing");
}
}
else
{
status.setCode(STATUS_BAD_REQUEST, "Incompatible node type. Required either fm:topic or fm:post. Received: " + node.type);
return null;
}
}
/** Returns the topic posts for a topic, ordered by creation date.

View File

@@ -0,0 +1,51 @@
/**
* Returns a data object that can be passed to the paged results template
* for rendering.
*
* @param nodes: The complete result set nodes
* @param index: the start index from which results should be returned
* @param count: the number of elements that should be returned
* @param extractDataFn: The function that extracts the data to be returned
* for each node in the final data set.
* The functions signature is name(index, node).
*
* Returns an array containing all topics found in the passed array.
* Filters out non-fm:topic nodes.
*/
function getPagedResultsData(nodes, index, count, extractDataFn)
{
var items = new Array();
var i;
var added = 0;
for (i = index; i < nodes.length && added < count; i++)
{
items.push(extractDataFn(nodes[i]));
added++;
}
return ({
"total" : nodes.length,
"pageSize" : count,
"startIndex" : index,
"itemCount" : items.length,
"items": items
});
}
/**
* Returns a list of topics, as returned by the lucene query
*/
function getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, ascending, index, count, extractDataFn)
{
var nodes = null;
if (sortAttribute != null)
{
nodes = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, ascending);
}
else
{
nodes = search.luceneSearch(luceneQuery);
}
return getPagedResultsData(nodes, index, count, extractDataFn);
}

View File

@@ -13,49 +13,49 @@
*/
function findNodeInSite()
{
var siteId = url.templateArgs.site;
var containerId = url.templateArgs.container;
var path = (url.templateArgs.path != undefined) ? url.templateArgs.path : "";
var siteId = url.templateArgs.site;
var containerId = url.templateArgs.container;
var path = (url.templateArgs.path != undefined) ? url.templateArgs.path : "";
// fetch site
var site = siteService.getSite(siteId);
if (site === null)
{
status.setCode(status.STATUS_NOT_FOUND, "Site " + siteId + " does not exist");
return null;
}
// fetch site
var site = siteService.getSite(siteId);
if (site === null)
{
status.setCode(status.STATUS_NOT_FOUND, "Site " + siteId + " does not exist");
return null;
}
// fetch container
var node = site.getContainer(containerId);
if (node === null)
{
status.setCode(status.STATUS_NOT_FOUND, "The container " + containerId + "could not be found in site " + siteId + ". (No write permission?)");
return null;
}
// try to fetch the the path is there is any
if ((path !== null) && (path != ""))
{
node = node.childByNamePath(path);
if (node === null)
{
status.setCode(status.STATUS_NOT_FOUND, "No node found for the given path: \"" + path + "\" in container " + containerId + " of site " + siteId);
return null;
}
}
// fetch container
var node = site.getContainer(containerId);
if (node === null)
{
status.setCode(status.STATUS_NOT_FOUND, "The container " + containerId + "could not be found in site " + siteId + ". (No write permission?)");
return null;
}
// try to fetch the the path is there is any
if ((path !== null) && (path.length > 0))
{
node = node.childByNamePath(path);
if (node === null)
{
status.setCode(status.STATUS_NOT_FOUND, "No node found for the given path: \"" + path + "\" in container " + containerId + " of site " + siteId);
return null;
}
}
return node;
}
function findFromReference()
{
var nodeRef = url.templateArgs.store_type + "://" + url.templateArgs.store_id + "/" + url.templateArgs.id;
var node = search.findNode(nodeRef);
if (node === null)
{
status.setCode(status.STATUS_NOT_FOUND, "Node " + nodeRef + " does not exist");
}
return node;
var nodeRef = url.templateArgs.store_type + "://" + url.templateArgs.store_id + "/" + url.templateArgs.id;
var node = search.findNode(nodeRef);
if (node === null)
{
status.setCode(status.STATUS_NOT_FOUND, "Node " + nodeRef + " does not exist");
}
return node;
}
/**
@@ -67,21 +67,21 @@ function findFromReference()
*/
function getRequestNode()
{
// check whether we got a node reference or a site related uri
var node = null;
if (url.templateArgs.store_type != undefined)
{
node = findFromReference();
}
// site related uri
else if (url.templateArgs.site != undefined)
{
node = findNodeInSite();
}
else
{
// unknown request params
status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "Unknown request parameters (webscript incorrectly configured?)");
}
return node;
// check whether we got a node reference or a site related uri
var node = null;
if (url.templateArgs.store_type != undefined)
{
node = findFromReference();
}
// site related uri
else if (url.templateArgs.site != undefined)
{
node = findNodeInSite();
}
else
{
// unknown request params
status.setCode(status.STATUS_INTERNAL_SERVER_ERROR, "Unknown request parameters (webscript incorrectly configured?)");
}
return node;
}