- new aspect cm:contentupdated used for forum/blog to mark updated posts

- aspect blg:released is used to mark a internally published post
- added missing I18N file for blog rss
- some ui enhancements, e.g. blog drafts won't show add comment box anymore

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@9881 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Michael Ru
2008-07-15 17:33:33 +00:00
parent 1632956b4a
commit 8d931598ce
12 changed files with 157 additions and 103 deletions

View File

@@ -4,57 +4,64 @@
</#macro> </#macro>
<#macro addContent item> <#macro addContent item>
<#assign maxTextLength=512> <#assign maxTextLength=512>
<#if (! contentFormat??) || contentFormat == "" || contentFormat == "full"> <#if (! contentFormat??) || contentFormat == "" || contentFormat == "full">
"content" : "${item.node.content?j_string}", "content" : "${item.node.content?j_string}",
<#elseif contentFormat == "htmlDigest"> <#elseif contentFormat == "htmlDigest">
<#if (item.node.content?length > maxTextLength)> <#if (item.node.content?length > maxTextLength)>
"content" : "${item.node.content?substring(0, maxTextLength)?j_string}", "content" : "${item.node.content?substring(0, maxTextLength)?j_string}",
<#else> <#else>
"content" : "${item.node.content?j_string}", "content" : "${item.node.content?j_string}",
</#if> </#if>
<#elseif contentFormat == "textDigest"> <#elseif contentFormat == "textDigest">
<#assign croppedTextContent=cropContent(item.node.properties.content, maxTextLength)> <#assign croppedTextContent=cropContent(item.node.properties.content, maxTextLength)>
"content" : "${croppedTextContent?j_string}", "content" : "${croppedTextContent?j_string}",
<#else> <#else>
<#-- no content returned --> <#-- no content returned -->
</#if> </#if>
</#macro> </#macro>
<#-- <#--
This template renders a blog post. This template renders a blog post.
--> -->
<#macro blogpostJSON item> <#macro blogpostJSON item>
{ {
"url" : "blog/post/node/${item.node.nodeRef?replace('://','/')}", "url" : "blog/post/node/${item.node.nodeRef?replace('://','/')}",
"commentsUrl" : "/node/${item.node.nodeRef?replace('://','/')}/comments", "commentsUrl" : "/node/${item.node.nodeRef?replace('://','/')}/comments",
"nodeRef" : "${item.node.nodeRef}", "nodeRef" : "${item.node.nodeRef}",
"name" : "${(item.node.properties.name!'')?j_string}", "name" : "${(item.node.properties.name!'')?j_string}",
"title" : "${(item.node.properties.title!'')?j_string}", "title" : "${(item.node.properties.title!'')?j_string}",
<@addContent item=item /> <@addContent item=item />
"author" : "${item.node.properties.creator?j_string}", "author" : "${item.node.properties.creator?j_string}",
"createdOn" : "${item.createdDate?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}", "createdOn" : "${item.createdDate?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}",
"modifiedOn" : "${item.modifiedDate?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}", "modifiedOn" : "${item.modifiedDate?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}",
"permissions" : {"edit" : true, "publishExt" : true, "delete" : true}, "permissions" : {"edit" : true, "publishExt" : true, "delete" : true},
"commentCount" : ${item.commentCount?c}, "commentCount" : ${item.commentCount?c},
"tags" : <@renderTags tags=item.tags />, "tags" : <@renderTags tags=item.tags />,
<#-- draft vs internal published --> <#-- draft vs internal published -->
"isDraft" : ${item.isDraft?string}, "isDraft" : ${item.isDraft?string},
<#-- true if the post has been updated --> <#if (! item.isDraft)>
"isUpdated" : ${item.isUpdated?string}, "releasedOn" : "${item.releasedDate?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}",
</#if>
<#-- external publishing -->
"isPublished" : ${(item.node.properties["blg:published"]!'false')?string}, <#-- true if the post has been updated -->
<#if (item.node.properties["blg:published"]?? && item.node.properties["blg:published"] == true)> "isUpdated" : ${item.isUpdated?string},
"publishedOn" : "${item.node.properties["blg:posted"]?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}", <#if (item.isUpdated)>
"updatedOn" : "${item.node.properties["blg:lastUpdate"]?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}", "updatedOn" : "${item.updatedDate?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}",
"postId" : "${item.node.properties["blg:postId"]!''}", </#if>
"postLink" : "${item.node.properties["blg:link"]!''}",
"outOfDate" : ${item.outOfDate?string} <#-- external publishing -->
</#if> "isPublished" : ${(item.node.properties["blg:published"]!'false')?string},
<#if (item.node.properties["blg:published"]?? && item.node.properties["blg:published"] == true)>
"publishedOn" : "${item.node.properties["blg:posted"]?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}",
"updatedOn" : "${item.node.properties["blg:lastUpdate"]?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}",
"postId" : "${item.node.properties["blg:postId"]!''}",
"postLink" : "${item.node.properties["blg:link"]!''}",
"outOfDate" : ${item.outOfDate?string}
</#if>
} }
</#macro> </#macro>

View File

@@ -1,24 +1,39 @@
<import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/comments/comments.lib.js"> <import resource="classpath:alfresco/templates/webscripts/org/alfresco/repository/comments/comments.lib.js">
const ASPECT_RELEASED = "blg:released";
const PROP_RELEASED = "blg:released";
const ASPECT_UPDATED = "cm:contentupdated";
const PROP_UPDATED = "cm:contentupdatedate";
function setOrUpdateReleasedAndUpdatedDates(node) function setOrUpdateReleasedAndUpdatedDates(node)
{ {
// check whether we already got the date tracking aspect, // check whether we already got the date tracking aspect,
// in this case we got an update // in this case we got an update
if (node.hasAspect("blg:releaseDetails")) if (node.hasAspect(ASPECT_RELEASED))
{ {
// just update the modified date if (node.hasAspect(ASPECT_UPDATED))
node.properties["blg:updated"] = new Date(); {
node.save(); // just update the modified date
node.properties[PROP_UPDATED] = new Date();
node.save();
}
else
{
// add the updated aspect
var props = new Array();
props[PROP_UPDATED] = new Date();
node.addAspect(ASPECT_UPDATED, props);
}
} }
else else
{ {
// attach the released/update date tracking aspect // attach the released aspect
var props = new Array(); var props = new Array();
props["blg:released"] = new Date(); var now = new Date();
props["blg:updated"] = new Date(); props[PROP_RELEASED] = now;
node.addAspect("blg:releaseDetails", props); node.addAspect(ASPECT_RELEASED, props);
// re-enable permission inheritance // re-enable permission inheritance which got disable for the draft
node.setInheritsPermissions(true); node.setInheritsPermissions(true);
} }
} }
@@ -33,25 +48,23 @@ function getBlogPostData(node)
data.commentCount = getCommentsCount(node); data.commentCount = getCommentsCount(node);
// draft // draft
data.isDraft = (! node.hasAspect("blg:releaseDetails")) || data.isDraft = ! node.hasAspect(ASPECT_RELEASED);
(node.properties["blg:released"] == undefined);
// use the released date if it exists
var createdDate = node.properties["cm:created"];
if (node.hasAspect("blg:releaseDetails") && node.properties["blg:released"] != undefined)
{
createdDate = node.properties["blg:released"];
}
data.createdDate = createdDate;
var modifiedDate = node.properties["cm:modified"];
if (node.hasAspect("blg:releaseDetails") && node.properties["blg:updated"] != undefined)
{
modifiedDate = node.properties["blg:updated"];
}
data.modifiedDate = modifiedDate;
// set the isUpdated flag // set the isUpdated flag
data.isUpdated = (modifiedDate - createdDate) > 5000; data.isUpdated = node.hasAspect(ASPECT_UPDATED);
// fetch all available dates
data.createdDate = node.properties["cm:created"];
data.modifiedDate = node.properties["cm:modified"];
if (node.hasAspect(ASPECT_RELEASED))
{
data.releasedDate = node.properties[PROP_RELEASED];
}
if (node.hasAspect(ASPECT_UPDATED))
{
data.updatedDate = node.properties[PROP_UPDATED];
}
// does the external post require an update? // does the external post require an update?
if ((node.properties["blg:lastUpdate"] != undefined)) if ((node.properties["blg:lastUpdate"] != undefined))

View File

@@ -8,8 +8,7 @@ function updateBlogPostDraftMode(postNode)
{ {
// make sure the user doesn't try to put a non-draft // make sure the user doesn't try to put a non-draft
// post back into draft node // post back into draft node
var currentDraft = (! postNode.hasAspect("blg:releaseDetails")) || var currentDraft = ! postNode.hasAspect("blg:released");
(postNode.properties["blg:released"] == undefined);
var isDraft = json.has("draft") && json.get("draft").toString() == "true"; var isDraft = json.has("draft") && json.get("draft").toString() == "true";
// requested draft, previously non-draft: throw an exception // requested draft, previously non-draft: throw an exception

View File

@@ -13,7 +13,7 @@ function getBlogPostList(node, index, count)
"+PATH:\"" + node.qnamePath + "/*\" "; "+PATH:\"" + node.qnamePath + "/*\" ";
// add the drafts part // add the drafts part
luceneQuery += "-ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}releaseDetails\" " + luceneQuery += "-ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}released\" " +
"+@cm\\:creator:\"" + person.properties.userName + "\""; "+@cm\\:creator:\"" + person.properties.userName + "\"";
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created"; var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created";

View File

@@ -13,7 +13,7 @@ function getBlogPostList(node, index, count)
" +PATH:\"" + node.qnamePath + "/*\" "; " +PATH:\"" + node.qnamePath + "/*\" ";
// add the drafts part // add the drafts part
luceneQuery += "+ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}releaseDetails\" " + luceneQuery += "+ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}released\" " +
"+@cm\\:creator:\"" + person.properties.userName + "\""; "+@cm\\:creator:\"" + person.properties.userName + "\"";

View File

@@ -15,10 +15,10 @@ function getBlogPostList(node, numdays, index, count)
// query information // query information
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" + var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" +
" +PATH:\"" + node.qnamePath + "/*\" " + " +PATH:\"" + node.qnamePath + "/*\" " +
" +ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}releaseDetails\" " + " +ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}released\" " +
getCreationDateRangeQuery(fromDate, null); getCreationDateRangeQuery(fromDate, null);
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created"; var sortAttribute = "@{http://www.alfresco.org/model/blogintegration/1.0}released";
// get the data // get the data
return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getBlogPostData); return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getBlogPostData);

View File

@@ -44,8 +44,9 @@ function getBlogPostMonths(node)
{ {
// query information // query information
var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" + var luceneQuery = " +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"" +
" +PATH:\"" + node.qnamePath + "/*\" "; " +PATH:\"" + node.qnamePath + "/*\" " +
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created"; " +ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}released\" ";
var sortAttribute = "@{http://www.alfresco.org/model/blogintegration/1.0}released";
nodes = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, true); nodes = search.luceneSearch(node.nodeRef.storeRef.toString(), luceneQuery, sortAttribute, true);
// will hold the months information // will hold the months information

View File

@@ -14,10 +14,10 @@ function getBlogPostList(node, fromDate, toDate, tag, index, count)
// include all published + my drafts // include all published + my drafts
luceneQuery += " ((" + luceneQuery += " ((" +
" -ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}releaseDetails\" " + " -ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}released\" " +
"+@cm\\:creator:\"" + person.properties.userName + "\"" + "+@cm\\:creator:\"" + person.properties.userName + "\"" +
") OR (" + ") OR (" +
" +ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}releaseDetails\" " + " +ASPECT:\"{http://www.alfresco.org/model/blogintegration/1.0}released\" " +
")) "; ")) ";
// date query ? // date query ?
@@ -32,7 +32,7 @@ function getBlogPostList(node, fromDate, toDate, tag, index, count)
luceneQuery += " +PATH:\"/cm:taggable/cm:" + tag /*ISO9075.encode(tag)*/ + "/member\" "; luceneQuery += " +PATH:\"/cm:taggable/cm:" + tag /*ISO9075.encode(tag)*/ + "/member\" ";
} }
var sortAttribute = "@{http://www.alfresco.org/model/content/1.0}created"; var sortAttribute = "@{http://www.alfresco.org/model/blogintegration/1.0}released";
// get the data // get the data
return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getBlogPostData); return getPagedResultsDataByLuceneQuery(node, luceneQuery, sortAttribute, false, index, count, getBlogPostData);

View File

@@ -56,6 +56,10 @@
"createdOn" : "${post.properties.created?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}", "createdOn" : "${post.properties.created?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}",
"modifiedOn" : "${post.properties.modified?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}", "modifiedOn" : "${post.properties.modified?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}",
"author" : "${post.properties.creator?j_string}", "author" : "${post.properties.creator?j_string}",
"isUpdated" : ${post.hasAspect("cm:contentupdated")?string},
<#if (post.hasAspect("cm:contentupdated"))>
"updatedOn" : "${post.properties["cm:contentupdatedate"]?string("MMM dd yyyy HH:mm:ss 'GMT'Z '('zzz')'")}",
</#if>
<@addContent post=post /> <@addContent post=post />
"replyCount" : <#if post.sourceAssocs["cm:references"]??>${post.sourceAssocs["cm:references"]?size?c}<#else>0</#if>, "replyCount" : <#if post.sourceAssocs["cm:references"]??>${post.sourceAssocs["cm:references"]?size?c}<#else>0</#if>,
"permissions" : { "edit": true, "delete" : true, "reply" : true } "permissions" : { "edit": true, "delete" : true, "reply" : true }

View File

@@ -35,6 +35,12 @@ function updatePost(topic, post)
post.content = content; post.content = content;
post.save(); post.save();
// add the content updated aspect
var now = new Date();
var props = new Array();
props["cm:contentupdatedate"] = now;
post.addAspect("cm:contentupdated", props);
// Only set the tags if it is a topic post // Only set the tags if it is a topic post
// as we currently don't support individual post tagging // as we currently don't support individual post tagging
if (topic != null) if (topic != null)

View File

@@ -327,9 +327,6 @@ public class BlogServiceTest extends BaseWebScriptTest
String name = item.getString("name"); String name = item.getString("name");
assertEquals(false, item.getBoolean("isUpdated")); assertEquals(false, item.getBoolean("isUpdated"));
// wait for 5 sec
Thread.sleep(5000);
item = updatePost(name, "new title", "new content", null, false, 200); item = updatePost(name, "new title", "new content", null, false, 200);
assertEquals(true, item.getBoolean("isUpdated")); assertEquals(true, item.getBoolean("isUpdated"));
assertEquals("new title", item.getString("title")); assertEquals("new title", item.getString("title"));

View File

@@ -160,13 +160,13 @@ public class DiscussionServiceTest extends BaseWebScriptTest
return item; return item;
} }
private JSONObject updatePost(String name, String title, String content, boolean isDraft, int expectedStatus) private JSONObject updatePost(String nodeRef, String title, String content, int expectedStatus)
throws Exception throws Exception
{ {
JSONObject post = new JSONObject(); JSONObject post = new JSONObject();
post.put("title", title); post.put("title", title);
post.put("content", content); post.put("content", content);
MockHttpServletResponse response = putRequest(URL_FORUM_POST + name, expectedStatus, post.toString(), "application/json"); MockHttpServletResponse response = putRequest(getPostUrl(nodeRef), expectedStatus, post.toString(), "application/json");
if (expectedStatus != 200) if (expectedStatus != 200)
{ {
@@ -219,24 +219,6 @@ public class DiscussionServiceTest extends BaseWebScriptTest
return result.getJSONObject("item"); return result.getJSONObject("item");
} }
private JSONObject updateComment(String nodeRef, String title, String content, int expectedStatus)
throws Exception
{
JSONObject comment = new JSONObject();
comment.put("title", title);
comment.put("content", content);
MockHttpServletResponse response = putRequest(getPostUrl(nodeRef), expectedStatus, comment.toString(), "application/json");
if (expectedStatus != 200)
{
return null;
}
//logger.debug("Comment updated: " + response.getContentAsString());
JSONObject result = new JSONObject(response.getContentAsString());
return result.getJSONObject("item");
}
// Tests // Tests
@@ -254,6 +236,30 @@ public class DiscussionServiceTest extends BaseWebScriptTest
getPost(item.getString("name"), 200); getPost(item.getString("name"), 200);
} }
public void testUpdateForumPost() throws Exception
{
String title = "test";
String content = "test";
JSONObject item = createPost(title, content, 200);
// check that the values
assertEquals(title, item.get("title"));
assertEquals(content, item.get("content"));
assertEquals(false, item.getBoolean("isUpdated"));
// fetch the post
getPost(item.getString("name"), 200);
String title2 = "test";
String content2 = "test";
item = updatePost(item.getString("nodeRef"), title2, content2, 200);
// check that the values
assertEquals(title2, item.get("title"));
assertEquals(content2, item.get("content"));
assertEquals(true, item.getBoolean("isUpdated"));
}
public void testGetAll() throws Exception public void testGetAll() throws Exception
{ {
String url = URL_FORUM_POSTS; String url = URL_FORUM_POSTS;
@@ -308,6 +314,27 @@ public class DiscussionServiceTest extends BaseWebScriptTest
assertEquals(1, item.getInt("replyCount")); assertEquals(1, item.getInt("replyCount"));
} }
public void testUpdateReply() throws Exception
{
// create a root post
JSONObject item = createPost("test", "test", 200);
String postName = item.getString("name");
String postNodeRef = item.getString("nodeRef");
// add a reply
JSONObject reply = createReply(postNodeRef, "test", "test", 200);
String replyNodeRef = reply.getString("nodeRef");
assertEquals("test", reply.getString("title"));
assertEquals("test", reply.getString("content"));
assertEquals(false, reply.getBoolean("isUpdated"));
// now update it
JSONObject reply2 = updatePost(reply.getString("nodeRef"), "test2", "test2", 200);
assertEquals("test2", reply2.getString("title"));
assertEquals("test2", reply2.getString("content"));
assertEquals(true, reply2.getBoolean("isUpdated"));
}
/* /*
public void testDeleteReplyPost() throws Exception public void testDeleteReplyPost() throws Exception
{ {