mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Revert "REPO-3235 Remove discussions and forums (#162)"
This reverts commit 30b7041c95
.
(Wrong merge, contains more than it should)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Branch specific configuration file for localisation scripts
|
# Branch specific configuration file for localisation scripts
|
||||||
|
|
||||||
MESSAGE_SEARCH_PATH="src/main/resources/alfresco/messages/admin-console*.properties src/main/resources/alfresco/messages/custommodel-restapi-messages*.properties src/main/resources/alfresco/messages/rest-framework-messages*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/admin-communitysummary.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/consoles/admin-repoconsole.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/consoles/admin-tenantconsole.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/consoles/admin-workflowconsole.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/support-tools/admin-nodebrowser.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/audit/entry*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/blogs/post/blog-post.delete*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/links/links-delete.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/links/links.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/links/links.put*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/person/user-csv-upload.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/slingshot/calendar/event.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/slingshot/calendar/event.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/slingshot/calendar/event.put*.properties"
|
MESSAGE_SEARCH_PATH="src/main/resources/alfresco/messages/admin-console*.properties src/main/resources/alfresco/messages/custommodel-restapi-messages*.properties src/main/resources/alfresco/messages/rest-framework-messages*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/admin-communitysummary.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/consoles/admin-repoconsole.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/consoles/admin-tenantconsole.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/consoles/admin-workflowconsole.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/admin/support-tools/admin-nodebrowser.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/audit/entry*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/blogs/post/blog-post.delete*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/discussions/posts/forum-post.delete*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/links/links-delete.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/links/links.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/links/links.put*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/person/user-csv-upload.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/slingshot/calendar/event.get*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/slingshot/calendar/event.post*.properties src/main/resources/alfresco/templates/webscripts/org/alfresco/slingshot/calendar/event.put*.properties"
|
||||||
|
|
||||||
EXCLUDED_FILES="src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/audit/control.properties"
|
EXCLUDED_FILES="src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/audit/control.properties"
|
||||||
|
|
||||||
|
2
pom.xml
2
pom.xml
@@ -35,7 +35,7 @@
|
|||||||
<dir.root>${project.build.directory}/alf_data</dir.root>
|
<dir.root>${project.build.directory}/alf_data</dir.root>
|
||||||
<img.exe>convert</img.exe>
|
<img.exe>convert</img.exe>
|
||||||
|
|
||||||
<dependency.alfresco-repository.version>7.53</dependency.alfresco-repository.version>
|
<dependency.alfresco-repository.version>7.52</dependency.alfresco-repository.version>
|
||||||
<dependency.alfresco-core.version>7.9</dependency.alfresco-core.version>
|
<dependency.alfresco-core.version>7.9</dependency.alfresco-core.version>
|
||||||
<dependency.alfresco-data-model.version>8.27</dependency.alfresco-data-model.version>
|
<dependency.alfresco-data-model.version>8.27</dependency.alfresco-data-model.version>
|
||||||
<dependency.alfresco-pdf-renderer.version>1.1</dependency.alfresco-pdf-renderer.version>
|
<dependency.alfresco-pdf-renderer.version>1.1</dependency.alfresco-pdf-renderer.version>
|
||||||
|
@@ -0,0 +1,603 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
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.content.MimetypeMap;
|
||||||
|
import org.alfresco.repo.discussion.DiscussionServiceImpl;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.repo.site.SiteServiceImpl;
|
||||||
|
import org.alfresco.service.cmr.activities.ActivityService;
|
||||||
|
import org.alfresco.service.cmr.discussion.DiscussionService;
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
|
import org.alfresco.service.cmr.security.AccessStatus;
|
||||||
|
import org.alfresco.service.cmr.security.NoSuchPersonException;
|
||||||
|
import org.alfresco.service.cmr.security.PermissionService;
|
||||||
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.alfresco.service.cmr.site.SiteService;
|
||||||
|
import org.alfresco.util.Pair;
|
||||||
|
import org.alfresco.util.ScriptPagingDetails;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.json.simple.parser.JSONParser;
|
||||||
|
import org.json.simple.parser.ParseException;
|
||||||
|
import org.springframework.extensions.webscripts.Cache;
|
||||||
|
import org.springframework.extensions.webscripts.DeclarativeWebScript;
|
||||||
|
import org.springframework.extensions.webscripts.Status;
|
||||||
|
import org.springframework.extensions.webscripts.WebScriptException;
|
||||||
|
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nick Burch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public abstract class AbstractDiscussionWebScript extends DeclarativeWebScript
|
||||||
|
{
|
||||||
|
public static final String DISCUSSIONS_SERVICE_ACTIVITY_APP_NAME = "discussions";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When no maximum or paging info is given, what should we use?
|
||||||
|
*/
|
||||||
|
protected static final int MAX_QUERY_ENTRY_COUNT = 1000;
|
||||||
|
|
||||||
|
private static Log logger = LogFactory.getLog(AbstractDiscussionWebScript.class);
|
||||||
|
|
||||||
|
protected static final String KEY_POSTDATA = "postData";
|
||||||
|
protected static final String KEY_IS_TOPIC_POST = "isTopicPost";
|
||||||
|
protected static final String KEY_TOPIC = "topic";
|
||||||
|
protected static final String KEY_POST = "post";
|
||||||
|
protected static final String KEY_CAN_EDIT = "canEdit";
|
||||||
|
protected static final String KEY_AUTHOR = "author";
|
||||||
|
|
||||||
|
// Injected services
|
||||||
|
protected NodeService nodeService;
|
||||||
|
protected SiteService siteService;
|
||||||
|
protected PersonService personService;
|
||||||
|
protected ActivityService activityService;
|
||||||
|
protected DiscussionService discussionService;
|
||||||
|
protected PermissionService permissionService;
|
||||||
|
|
||||||
|
public void setNodeService(NodeService nodeService)
|
||||||
|
{
|
||||||
|
this.nodeService = nodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSiteService(SiteService siteService)
|
||||||
|
{
|
||||||
|
this.siteService = siteService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPersonService(PersonService personService)
|
||||||
|
{
|
||||||
|
this.personService = personService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActivityService(ActivityService activityService)
|
||||||
|
{
|
||||||
|
this.activityService = activityService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDiscussionService(DiscussionService discussionService)
|
||||||
|
{
|
||||||
|
this.discussionService = discussionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermissionService(PermissionService permissionService)
|
||||||
|
{
|
||||||
|
this.permissionService = permissionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected String getOrNull(JSONObject json, String key)
|
||||||
|
{
|
||||||
|
if (json.containsKey(key))
|
||||||
|
{
|
||||||
|
return (String)json.get(key);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds up a listing Paging request, based on the arguments
|
||||||
|
* specified in the URL
|
||||||
|
*/
|
||||||
|
protected PagingRequest buildPagingRequest(WebScriptRequest req)
|
||||||
|
{
|
||||||
|
return new ScriptPagingDetails(req, MAX_QUERY_ENTRY_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> getTags(JSONObject json)
|
||||||
|
{
|
||||||
|
List<String> tags = null;
|
||||||
|
if (json.containsKey("tags"))
|
||||||
|
{
|
||||||
|
// Is it "tags":"" or "tags":[...] ?
|
||||||
|
if (json.get("tags") instanceof String)
|
||||||
|
{
|
||||||
|
// This is normally an empty string, skip
|
||||||
|
String tagsS = (String)json.get("tags");
|
||||||
|
if ("".equals(tagsS))
|
||||||
|
{
|
||||||
|
// No tags were given
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Log, and treat as empty
|
||||||
|
logger.warn("Unexpected tag data: " + tagsS);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tags = new ArrayList<String>();
|
||||||
|
JSONArray jsTags = (JSONArray)json.get("tags");
|
||||||
|
for (int i=0; i<jsTags.size(); i++)
|
||||||
|
{
|
||||||
|
tags.add( (String)jsTags.get(i) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an activity entry for the discussion item
|
||||||
|
*
|
||||||
|
* @param thing Either post or reply
|
||||||
|
* @param event One of created, updated, deleted
|
||||||
|
*/
|
||||||
|
protected void addActivityEntry(String thing, String event, TopicInfo topic,
|
||||||
|
PostInfo post, SiteInfo site, WebScriptRequest req, JSONObject json)
|
||||||
|
{
|
||||||
|
// We can only add activities against a site
|
||||||
|
if (site == null)
|
||||||
|
{
|
||||||
|
logger.info("Unable to add activity entry for " + thing + " " + event + " as no site given");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// What page is this for?
|
||||||
|
String page = req.getParameter("page");
|
||||||
|
if (page == null && json != null)
|
||||||
|
{
|
||||||
|
if (json.containsKey("page"))
|
||||||
|
{
|
||||||
|
page = (String)json.get("page");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (page == null)
|
||||||
|
{
|
||||||
|
// Default
|
||||||
|
page = "discussions-topicview";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the title
|
||||||
|
String title = topic.getTitle();
|
||||||
|
if (post != null)
|
||||||
|
{
|
||||||
|
String postTitle = post.getTitle();
|
||||||
|
if (postTitle != null && postTitle.length() > 0)
|
||||||
|
{
|
||||||
|
title = postTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JSONObject params = new JSONObject();
|
||||||
|
params.put("topicId", topic.getSystemName());
|
||||||
|
|
||||||
|
JSONObject activity = new JSONObject();
|
||||||
|
activity.put("title", title);
|
||||||
|
activity.put("page", page + "?topicId=" + topic.getSystemName());
|
||||||
|
activity.put("params", params);
|
||||||
|
|
||||||
|
activityService.postActivity(
|
||||||
|
"org.alfresco.discussions." + thing + "-" + event,
|
||||||
|
site.getShortName(),
|
||||||
|
DISCUSSIONS_SERVICE_ACTIVITY_APP_NAME,
|
||||||
|
activity.toString());
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
// Warn, but carry on
|
||||||
|
logger.warn("Error adding discussions " + thing + " " + event + " to activities feed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the current user allowed to edit this post?
|
||||||
|
* In order to be deemed allowed, you first need write
|
||||||
|
* permissions on the underlying node of the post.
|
||||||
|
* You then also need to either be the cm:creator of
|
||||||
|
* the post node, or a site manager
|
||||||
|
*/
|
||||||
|
protected boolean canUserEditPost(PostInfo post, SiteInfo site)
|
||||||
|
{
|
||||||
|
// Are they OK on the node?
|
||||||
|
AccessStatus canEdit = permissionService.hasPermission(post.getNodeRef(), PermissionService.WRITE);
|
||||||
|
if (canEdit == AccessStatus.ALLOWED)
|
||||||
|
{
|
||||||
|
// Only the creator and site managers may edit
|
||||||
|
String user = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
|
if (post.getCreator().equals(user))
|
||||||
|
{
|
||||||
|
// It's their post
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (site != null)
|
||||||
|
{
|
||||||
|
String role = siteService.getMembersRole(site.getShortName(), user);
|
||||||
|
if (SiteServiceImpl.SITE_MANAGER.equals(role))
|
||||||
|
{
|
||||||
|
// Managers may edit
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If in doubt, you may not edit
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object buildPerson(String username)
|
||||||
|
{
|
||||||
|
// Empty string needed if the user can't be found
|
||||||
|
Object noSuchPersonResponse = "";
|
||||||
|
|
||||||
|
if (username == null || username.length() == 0)
|
||||||
|
{
|
||||||
|
return noSuchPersonResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Will turn into a Script Node needed of the person
|
||||||
|
NodeRef person = personService.getPerson(username);
|
||||||
|
return person;
|
||||||
|
}
|
||||||
|
catch(NoSuchPersonException e)
|
||||||
|
{
|
||||||
|
// This is normally caused by the person having been deleted
|
||||||
|
return noSuchPersonResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Was topicpost.lib.js getReplyPostData
|
||||||
|
*
|
||||||
|
* TODO Switch the FTL to prefer the Info object rather than the ScriptNode
|
||||||
|
*/
|
||||||
|
protected Map<String, Object> renderPost(PostInfo post, SiteInfo site)
|
||||||
|
{
|
||||||
|
Map<String, Object> item = new HashMap<String, Object>();
|
||||||
|
item.put(KEY_IS_TOPIC_POST, false);
|
||||||
|
item.put(KEY_POST, post.getNodeRef());
|
||||||
|
item.put(KEY_CAN_EDIT, canUserEditPost(post, site));
|
||||||
|
item.put(KEY_AUTHOR, buildPerson(post.getCreator()));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Was topicpost.lib.js getTopicPostData / getTopicPostDataFromTopicAndPosts
|
||||||
|
*
|
||||||
|
* TODO Switch the FTL to prefer the Info object rather than the ScriptNode
|
||||||
|
*/
|
||||||
|
protected Map<String, Object> renderTopic(TopicInfo topic, SiteInfo site)
|
||||||
|
{
|
||||||
|
// Fetch the primary post
|
||||||
|
PostInfo primaryPost = discussionService.getPrimaryPost(topic);
|
||||||
|
if (primaryPost == null)
|
||||||
|
{
|
||||||
|
throw new WebScriptException(Status.STATUS_PRECONDITION_FAILED,
|
||||||
|
"First (primary) post was missing from the topic, can't fetch");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the most recent reply
|
||||||
|
PostInfo mostRecentPost = discussionService.getMostRecentPost(topic);
|
||||||
|
|
||||||
|
// Find out how many replies there are
|
||||||
|
int numReplies;
|
||||||
|
if (mostRecentPost.getNodeRef().equals( primaryPost.getNodeRef() ))
|
||||||
|
{
|
||||||
|
// Only the one post in the topic
|
||||||
|
mostRecentPost = null;
|
||||||
|
numReplies = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use this trick to get the number of posts in the topic,
|
||||||
|
// but without needing to get lots of data and objects
|
||||||
|
PagingRequest paging = new PagingRequest(1);
|
||||||
|
paging.setRequestTotalCountMax(MAX_QUERY_ENTRY_COUNT);
|
||||||
|
PagingResults<PostInfo> posts = discussionService.listPosts(topic, paging);
|
||||||
|
|
||||||
|
// The primary post is in the list, so exclude from the reply count
|
||||||
|
numReplies = posts.getTotalResultCount().getFirst() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the details
|
||||||
|
Map<String, Object> item = new HashMap<String, Object>();
|
||||||
|
item.put(KEY_IS_TOPIC_POST, true);
|
||||||
|
item.put(KEY_TOPIC, topic.getNodeRef());
|
||||||
|
item.put(KEY_POST, primaryPost.getNodeRef());
|
||||||
|
item.put(KEY_CAN_EDIT, canUserEditPost(primaryPost, site));
|
||||||
|
item.put(KEY_AUTHOR, buildPerson(topic.getCreator()));
|
||||||
|
|
||||||
|
// The reply count is one less than all posts (first is the primary one)
|
||||||
|
item.put("totalReplyCount", numReplies);
|
||||||
|
|
||||||
|
// Add the topic site
|
||||||
|
item.put("site", topic.getShortSiteName());
|
||||||
|
|
||||||
|
// We want details on the most recent post
|
||||||
|
if (mostRecentPost != null)
|
||||||
|
{
|
||||||
|
item.put("lastReply", mostRecentPost.getNodeRef());
|
||||||
|
item.put("lastReplyBy", buildPerson(mostRecentPost.getCreator()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include the tags
|
||||||
|
item.put("tags", topic.getTags());
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Renders out the list of topics
|
||||||
|
* TODO Fetch the post data in one go, rather than one at a time
|
||||||
|
*/
|
||||||
|
protected Map<String, Object> renderTopics(PagingResults<TopicInfo> topics,
|
||||||
|
PagingRequest paging, SiteInfo site)
|
||||||
|
{
|
||||||
|
return renderTopics(topics.getPage(), topics.getTotalResultCount(), paging, site);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Renders out the list of topics
|
||||||
|
* TODO Fetch the post data in one go, rather than one at a time
|
||||||
|
*/
|
||||||
|
protected Map<String, Object> renderTopics(List<TopicInfo> topics,
|
||||||
|
Pair<Integer,Integer> size, PagingRequest paging, SiteInfo site)
|
||||||
|
{
|
||||||
|
Map<String, Object> model = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
// Paging info
|
||||||
|
model.put("total", size.getFirst());
|
||||||
|
model.put("pageSize", paging.getMaxItems());
|
||||||
|
model.put("startIndex", paging.getSkipCount());
|
||||||
|
model.put("itemCount", topics.size());
|
||||||
|
|
||||||
|
// Data
|
||||||
|
List<Map<String,Object>> items = new ArrayList<Map<String,Object>>();
|
||||||
|
for (TopicInfo topic : topics)
|
||||||
|
{
|
||||||
|
// ACE-772 fix of incorrect display of topics into "My Discussions" dashlet.
|
||||||
|
// Into "My Discussions" dashlet forum topic will be displayed only if user is a member of that site.
|
||||||
|
if (null == site && null != topic.getShortSiteName())
|
||||||
|
{
|
||||||
|
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
|
String siteShortName = topic.getShortSiteName();
|
||||||
|
boolean isSiteMember = siteService.isMember(siteShortName, currentUser);
|
||||||
|
|
||||||
|
if (isSiteMember)
|
||||||
|
{
|
||||||
|
items.add(renderTopic(topic, site));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Display all topics on the forum of the site.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
items.add(renderTopic(topic, site));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model.put("items", items);
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, Object> buildCommonModel(SiteInfo site, TopicInfo topic,
|
||||||
|
PostInfo post, WebScriptRequest req)
|
||||||
|
{
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = new HashMap<String, Object>();
|
||||||
|
model.put(KEY_TOPIC, topic);
|
||||||
|
model.put(KEY_POST, post);
|
||||||
|
|
||||||
|
// Capture the site details only if site based
|
||||||
|
if (site != null)
|
||||||
|
{
|
||||||
|
model.put("siteId", site.getShortName());
|
||||||
|
model.put("site", site);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The limit on the length of the content to be returned
|
||||||
|
int contentLength = -1;
|
||||||
|
String contentLengthS = req.getParameter("contentLength");
|
||||||
|
if (contentLengthS != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
contentLength = Integer.parseInt(contentLengthS);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e)
|
||||||
|
{
|
||||||
|
logger.info("Skipping invalid length " + contentLengthS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model.put("contentLength", contentLength);
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(WebScriptRequest req,
|
||||||
|
Status status, Cache cache)
|
||||||
|
{
|
||||||
|
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
|
||||||
|
if (templateVars == null)
|
||||||
|
{
|
||||||
|
String error = "No parameters supplied";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Parse the JSON, if supplied
|
||||||
|
JSONObject json = null;
|
||||||
|
String contentType = req.getContentType();
|
||||||
|
if (contentType != null && contentType.indexOf(';') != -1)
|
||||||
|
{
|
||||||
|
contentType = contentType.substring(0, contentType.indexOf(';'));
|
||||||
|
}
|
||||||
|
if (MimetypeMap.MIMETYPE_JSON.equals(contentType))
|
||||||
|
{
|
||||||
|
JSONParser parser = new JSONParser();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
json = (JSONObject)parser.parse(req.getContent().getContent());
|
||||||
|
}
|
||||||
|
catch (IOException io)
|
||||||
|
{
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Invalid JSON: " + io.getMessage());
|
||||||
|
}
|
||||||
|
catch (ParseException pe)
|
||||||
|
{
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Invalid JSON: " + pe.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Did they request it by node reference or site?
|
||||||
|
NodeRef nodeRef = null;
|
||||||
|
SiteInfo site = null;
|
||||||
|
TopicInfo topic = null;
|
||||||
|
PostInfo post = null;
|
||||||
|
|
||||||
|
if (templateVars.containsKey("site"))
|
||||||
|
{
|
||||||
|
// Site, and optionally topic
|
||||||
|
String siteName = templateVars.get("site");
|
||||||
|
site = siteService.getSite(siteName);
|
||||||
|
if (site == null)
|
||||||
|
{
|
||||||
|
String error = "Could not find site: " + siteName;
|
||||||
|
throw new WebScriptException(Status.STATUS_NOT_FOUND, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Did they give a topic name too?
|
||||||
|
if (templateVars.containsKey("path"))
|
||||||
|
{
|
||||||
|
String name = templateVars.get("path");
|
||||||
|
topic = discussionService.getTopic(site.getShortName(), name);
|
||||||
|
|
||||||
|
if (topic == null)
|
||||||
|
{
|
||||||
|
String error = "Could not find topic '" + name + "' for site '" +
|
||||||
|
site.getShortName() + "'";
|
||||||
|
throw new WebScriptException(Status.STATUS_NOT_FOUND, error);
|
||||||
|
}
|
||||||
|
nodeRef = topic.getNodeRef();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The NodeRef is the container (if it exists)
|
||||||
|
if (siteService.hasContainer(siteName, DiscussionServiceImpl.DISCUSSION_COMPONENT))
|
||||||
|
{
|
||||||
|
nodeRef = siteService.getContainer(siteName, DiscussionServiceImpl.DISCUSSION_COMPONENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (templateVars.containsKey("store_type") &&
|
||||||
|
templateVars.containsKey("store_id") &&
|
||||||
|
templateVars.containsKey("id"))
|
||||||
|
{
|
||||||
|
// NodeRef, normally Topic or Discussion
|
||||||
|
StoreRef store = new StoreRef(
|
||||||
|
templateVars.get("store_type"),
|
||||||
|
templateVars.get("store_id"));
|
||||||
|
|
||||||
|
nodeRef = new NodeRef(store, templateVars.get("id"));
|
||||||
|
if (! nodeService.exists(nodeRef))
|
||||||
|
{
|
||||||
|
String error = "Could not find node: " + nodeRef;
|
||||||
|
throw new WebScriptException(Status.STATUS_NOT_FOUND, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to build the appropriate object for it
|
||||||
|
Pair<TopicInfo,PostInfo> objects = discussionService.getForNodeRef(nodeRef);
|
||||||
|
if (objects != null)
|
||||||
|
{
|
||||||
|
topic = objects.getFirst();
|
||||||
|
post = objects.getSecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if it's actually attached to a site
|
||||||
|
if (topic != null)
|
||||||
|
{
|
||||||
|
NodeRef container = topic.getContainerNodeRef();
|
||||||
|
if (container != null)
|
||||||
|
{
|
||||||
|
NodeRef maybeSite = nodeService.getPrimaryParent(container).getParentRef();
|
||||||
|
if (maybeSite != null)
|
||||||
|
{
|
||||||
|
// Try to make it a site, will return Null if it isn't one
|
||||||
|
site = siteService.getSite(maybeSite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String error = "Unsupported template parameters found";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Have the real work done
|
||||||
|
return executeImpl(site, nodeRef, topic, post, req, json, status, cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Map<String, Object> executeImpl(SiteInfo site,
|
||||||
|
NodeRef nodeRef, TopicInfo topic, PostInfo post,
|
||||||
|
WebScriptRequest req, JSONObject json, Status status, Cache cache);
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
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 forum post deleting forum-post.delete webscript.
|
||||||
|
*
|
||||||
|
* @author Nick Burch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public class ForumPostDelete extends AbstractDiscussionWebScript
|
||||||
|
{
|
||||||
|
private static final String MSG_NODE_MARKED_REMOVED = "forum-post.msg.marked.removed";
|
||||||
|
private static final String MSG_NODE_DELETED = "forum-post.msg.deleted";
|
||||||
|
private static final String DELETED_POST_TEXT = "[[deleted]]";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(SiteInfo site, NodeRef nodeRef,
|
||||||
|
TopicInfo topic, PostInfo post, WebScriptRequest req, JSONObject json,
|
||||||
|
Status status, Cache cache)
|
||||||
|
{
|
||||||
|
final ResourceBundle rb = getResources();
|
||||||
|
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = buildCommonModel(site, topic, post, req);
|
||||||
|
|
||||||
|
|
||||||
|
// Are we deleting a topic, or a post in it?
|
||||||
|
String message = null;
|
||||||
|
if (post != null)
|
||||||
|
{
|
||||||
|
message = doDeletePost(topic, post, rb);
|
||||||
|
}
|
||||||
|
else if (topic != null)
|
||||||
|
{
|
||||||
|
message = doDeleteTopic(topic, site, req, json, rb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String error = "Node was of the wrong type, only Topic and Post are supported";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Finish the model and return
|
||||||
|
model.put("message", message);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String doDeleteTopic(TopicInfo topic, SiteInfo site,
|
||||||
|
WebScriptRequest req, JSONObject json, ResourceBundle rb)
|
||||||
|
{
|
||||||
|
// Delete the topic, which removes all its posts too
|
||||||
|
discussionService.deleteTopic(topic);
|
||||||
|
|
||||||
|
// Add an activity entry for this if it's site based
|
||||||
|
if (site != null)
|
||||||
|
{
|
||||||
|
addActivityEntry("post", "deleted", topic, null, site, req, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
// All done
|
||||||
|
String message = rb.getString(MSG_NODE_DELETED);
|
||||||
|
|
||||||
|
return MessageFormat.format(message, topic.getNodeRef());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We can't just delete posts with replies attached to them,
|
||||||
|
* as that breaks the reply threading.
|
||||||
|
* For that reason, we mark deleted posts with a special
|
||||||
|
* text contents.
|
||||||
|
* TODO If a post has no replies, then delete it fully
|
||||||
|
*/
|
||||||
|
private String doDeletePost(TopicInfo topic, PostInfo post, ResourceBundle rb)
|
||||||
|
{
|
||||||
|
// Set the marker text and save
|
||||||
|
post.setTitle(DELETED_POST_TEXT);
|
||||||
|
post.setContents(DELETED_POST_TEXT);
|
||||||
|
discussionService.updatePost(post);
|
||||||
|
|
||||||
|
// Note - we don't add activity feed entries for deleted posts
|
||||||
|
// Only deleted whole topic qualify for that at the moment
|
||||||
|
|
||||||
|
String message = rb.getString(MSG_NODE_MARKED_REMOVED);
|
||||||
|
return MessageFormat.format(message, post.getNodeRef());
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
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 discussions page fetching forum-post.get webscript.
|
||||||
|
*
|
||||||
|
* @author Nick Burch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public class ForumPostGet extends AbstractDiscussionWebScript
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(SiteInfo site, NodeRef nodeRef,
|
||||||
|
TopicInfo topic, PostInfo post, WebScriptRequest req, JSONObject json,
|
||||||
|
Status status, Cache cache)
|
||||||
|
{
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = buildCommonModel(site, topic, post, req);
|
||||||
|
|
||||||
|
// Did they want just one post, or the whole of the topic?
|
||||||
|
if (post != null)
|
||||||
|
{
|
||||||
|
model.put(KEY_POSTDATA, renderPost(post, site));
|
||||||
|
}
|
||||||
|
else if (topic != null)
|
||||||
|
{
|
||||||
|
model.put(KEY_POSTDATA, renderTopic(topic, site));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String error = "Node was of the wrong type, only Topic and Post are supported";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
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 discussions page editing forum-post.put webscript.
|
||||||
|
*
|
||||||
|
* @author Nick Burch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public class ForumPostPut extends AbstractDiscussionWebScript
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(SiteInfo site, NodeRef nodeRef,
|
||||||
|
TopicInfo topic, PostInfo post, WebScriptRequest req, JSONObject json,
|
||||||
|
Status status, Cache cache)
|
||||||
|
{
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = buildCommonModel(site, topic, post, req);
|
||||||
|
|
||||||
|
// Did they want to change a reply or the whole topic?
|
||||||
|
if (post != null)
|
||||||
|
{
|
||||||
|
// Update the specified post
|
||||||
|
doUpdatePost(post, post.getTopic(), req, json);
|
||||||
|
|
||||||
|
// Add the activity entry for the reply change
|
||||||
|
addActivityEntry("reply", "updated", post.getTopic(), post, site, req, json);
|
||||||
|
|
||||||
|
// Build the JSON for just this post
|
||||||
|
model.put(KEY_POSTDATA, renderPost(post, site));
|
||||||
|
}
|
||||||
|
else if (topic != null)
|
||||||
|
{
|
||||||
|
// Update the primary post of the topic
|
||||||
|
post = discussionService.getPrimaryPost(topic);
|
||||||
|
if (post == null)
|
||||||
|
{
|
||||||
|
throw new WebScriptException(Status.STATUS_PRECONDITION_FAILED,
|
||||||
|
"First (primary) post was missing from the topic, can't fetch");
|
||||||
|
}
|
||||||
|
doUpdatePost(post, topic, req, json);
|
||||||
|
|
||||||
|
// Add the activity entry for the topic change
|
||||||
|
addActivityEntry("post", "updated", topic, null, site, req, json);
|
||||||
|
|
||||||
|
// Build the JSON for the whole topic
|
||||||
|
model.put(KEY_POSTDATA, renderTopic(topic, site));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String error = "Node was of the wrong type, only Topic and Post are supported";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doUpdatePost(PostInfo post, TopicInfo topic, WebScriptRequest req,
|
||||||
|
JSONObject json)
|
||||||
|
{
|
||||||
|
boolean updateTopic = false;
|
||||||
|
// Fetch the details from the JSON
|
||||||
|
|
||||||
|
// Update the titles on the post and it's topic
|
||||||
|
if (json.containsKey("title"))
|
||||||
|
{
|
||||||
|
String title = (String)json.get("title");
|
||||||
|
post.setTitle(title);
|
||||||
|
if (title.length() > 0)
|
||||||
|
{
|
||||||
|
updateTopic = true;
|
||||||
|
topic.setTitle(title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contents is on the post
|
||||||
|
if (json.containsKey("content"))
|
||||||
|
{
|
||||||
|
post.setContents((String)json.get("content"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tags are on the topic
|
||||||
|
if (json.containsKey("tags"))
|
||||||
|
{
|
||||||
|
topic.getTags().clear();
|
||||||
|
|
||||||
|
List<String> tags = getTags(json);
|
||||||
|
if (tags != null)
|
||||||
|
{
|
||||||
|
topic.getTags().addAll(tags);
|
||||||
|
}
|
||||||
|
updateTopic = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the topic and the post
|
||||||
|
if (updateTopic == true)
|
||||||
|
{
|
||||||
|
discussionService.updateTopic(topic);
|
||||||
|
}
|
||||||
|
discussionService.updatePost(post);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.PostWithReplies;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
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 discussions page creating forum-post-replies.get webscript.
|
||||||
|
*
|
||||||
|
* @author Nick Burch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public class ForumPostRepliesGet extends AbstractDiscussionWebScript
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(SiteInfo site, NodeRef nodeRef,
|
||||||
|
TopicInfo topic, PostInfo post, WebScriptRequest req, JSONObject json,
|
||||||
|
Status status, Cache cache)
|
||||||
|
{
|
||||||
|
// How many levels did they want?
|
||||||
|
int levels = 1;
|
||||||
|
String levelsS = req.getParameter("levels");
|
||||||
|
if (levelsS != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
levels = Integer.parseInt(levelsS);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e)
|
||||||
|
{
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Level depth parameter invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the replies
|
||||||
|
PostWithReplies replies;
|
||||||
|
if (post != null)
|
||||||
|
{
|
||||||
|
replies = discussionService.listPostReplies(post, levels);
|
||||||
|
}
|
||||||
|
else if (topic != null)
|
||||||
|
{
|
||||||
|
replies = discussionService.listPostReplies(topic, levels);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String error = "Node was of the wrong type, only Topic and Post are supported";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = buildCommonModel(site, topic, post, req);
|
||||||
|
|
||||||
|
// Build the JSON for the replies
|
||||||
|
model.put("data", renderReplies(replies, site).get("children"));
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> renderReplies(PostWithReplies replies, SiteInfo site)
|
||||||
|
{
|
||||||
|
Map<String, Object> reply = renderPost(replies.getPost(), site);
|
||||||
|
reply.put("childCount", replies.getReplies().size());
|
||||||
|
|
||||||
|
List<Map<String,Object>> r = new ArrayList<Map<String,Object>>();
|
||||||
|
for (PostWithReplies child : replies.getReplies())
|
||||||
|
{
|
||||||
|
r.add(renderReplies(child, site));
|
||||||
|
}
|
||||||
|
reply.put("children", r);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
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 discussions page creating forum-post-replies.post webscript.
|
||||||
|
*
|
||||||
|
* @author Nick Burch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public class ForumPostRepliesPost extends AbstractDiscussionWebScript
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(SiteInfo site, NodeRef nodeRef,
|
||||||
|
TopicInfo topic, PostInfo post, WebScriptRequest req, JSONObject json,
|
||||||
|
Status status, Cache cache)
|
||||||
|
{
|
||||||
|
// If they're trying to create a reply to a topic, they actually
|
||||||
|
// mean to create the reply on the primary post
|
||||||
|
if (post == null)
|
||||||
|
{
|
||||||
|
post = discussionService.getPrimaryPost(topic);
|
||||||
|
if (post == null)
|
||||||
|
{
|
||||||
|
throw new WebScriptException(Status.STATUS_PRECONDITION_FAILED,
|
||||||
|
"First (primary) post was missing from the topic, can't fetch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (topic == null)
|
||||||
|
{
|
||||||
|
String error = "Node was of the wrong type, only Topic and Post are supported";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Have the reply created
|
||||||
|
PostInfo reply = doCreatePost(post, topic, req, json);
|
||||||
|
|
||||||
|
// Add the activity entry for the reply change
|
||||||
|
addActivityEntry("reply", "created", topic, reply, site, req, json);
|
||||||
|
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = buildCommonModel(site, topic, reply, req);
|
||||||
|
|
||||||
|
// Build the JSON for the new reply post
|
||||||
|
model.put(KEY_POSTDATA, renderPost(reply, site));
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PostInfo doCreatePost(PostInfo post, TopicInfo topic, WebScriptRequest req,
|
||||||
|
JSONObject json)
|
||||||
|
{
|
||||||
|
// Fetch the details from the JSON
|
||||||
|
String title = null;
|
||||||
|
if (json.containsKey("title"))
|
||||||
|
{
|
||||||
|
title = (String)json.get("title");
|
||||||
|
}
|
||||||
|
|
||||||
|
String contents = null;
|
||||||
|
if (json.containsKey("content"))
|
||||||
|
{
|
||||||
|
contents = (String)json.get("content");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Create the reply
|
||||||
|
PostInfo reply = discussionService.createReply(post, contents);
|
||||||
|
|
||||||
|
// Set the title if needed (it normally isn't)
|
||||||
|
if (title != null && title.length() > 0)
|
||||||
|
{
|
||||||
|
nodeService.setProperty(reply.getNodeRef(), ContentModel.PROP_TITLE, title);
|
||||||
|
reply = discussionService.getPost(topic, reply.getSystemName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
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 discussions page editing forum-posts.post webscript.
|
||||||
|
*
|
||||||
|
* @author Nick Burch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public class ForumTopicPost extends AbstractDiscussionWebScript
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(SiteInfo site, NodeRef nodeRef,
|
||||||
|
TopicInfo topic, PostInfo post, WebScriptRequest req, JSONObject json,
|
||||||
|
Status status, Cache cache)
|
||||||
|
{
|
||||||
|
// They shouldn't be adding to an existing Post or Topic
|
||||||
|
if (topic != null || post != null)
|
||||||
|
{
|
||||||
|
String error = "Can't create a new Topic inside an existing Topic or Post";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Grab the details of the new Topic and Post
|
||||||
|
String title = "";
|
||||||
|
String contents = "";
|
||||||
|
if (json.containsKey("title"))
|
||||||
|
{
|
||||||
|
title = (String)json.get("title");
|
||||||
|
}
|
||||||
|
if (json.containsKey("content"))
|
||||||
|
{
|
||||||
|
contents = (String)json.get("content");
|
||||||
|
}
|
||||||
|
List<String> tags = getTags(json);
|
||||||
|
|
||||||
|
|
||||||
|
// Have the topic created
|
||||||
|
if (site != null)
|
||||||
|
{
|
||||||
|
topic = discussionService.createTopic(site.getShortName(), title);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
topic = discussionService.createTopic(nodeRef, title);
|
||||||
|
}
|
||||||
|
if (tags != null && tags.size() > 0)
|
||||||
|
{
|
||||||
|
topic.getTags().clear();
|
||||||
|
topic.getTags().addAll(tags);
|
||||||
|
discussionService.updateTopic(topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Have the primary post created
|
||||||
|
post = discussionService.createPost(topic, contents);
|
||||||
|
|
||||||
|
|
||||||
|
// Record the activity
|
||||||
|
addActivityEntry("post", "created", topic, post, site, req, json);
|
||||||
|
|
||||||
|
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = buildCommonModel(site, topic, post, req);
|
||||||
|
|
||||||
|
// Build the JSON for the whole topic
|
||||||
|
model.put(KEY_POSTDATA, renderTopic(topic, site));
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,414 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import org.alfresco.query.EmptyPagingResults;
|
||||||
|
import org.alfresco.query.PagingRequest;
|
||||||
|
import org.alfresco.query.PagingResults;
|
||||||
|
import org.alfresco.repo.discussion.TopicInfoImpl;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
|
import org.alfresco.service.cmr.search.LimitBy;
|
||||||
|
import org.alfresco.service.cmr.search.ResultSet;
|
||||||
|
import org.alfresco.service.cmr.search.ResultSetRow;
|
||||||
|
import org.alfresco.service.cmr.search.SearchParameters;
|
||||||
|
import org.alfresco.service.cmr.search.SearchService;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.alfresco.util.ISO9075;
|
||||||
|
import org.alfresco.util.Pair;
|
||||||
|
import org.alfresco.util.ScriptPagingDetails;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.springframework.extensions.webscripts.Cache;
|
||||||
|
import org.springframework.extensions.webscripts.Status;
|
||||||
|
import org.springframework.extensions.webscripts.WebScriptException;
|
||||||
|
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets topics matching the filters passed to it in the URL.
|
||||||
|
*
|
||||||
|
* topics = 'mine' (searches for posts by the user) or 'all' (ignores the author in the search)
|
||||||
|
* history = days in the past to search
|
||||||
|
* resultSize = the number of topics returned in the results
|
||||||
|
*
|
||||||
|
* @author Jamie Allison
|
||||||
|
*/
|
||||||
|
public class ForumTopicsFilteredGet extends AbstractDiscussionWebScript
|
||||||
|
{
|
||||||
|
//Filter Defaults
|
||||||
|
protected static final String DEFAULT_TOPIC_AUTHOR = "mine";
|
||||||
|
protected static final int DEFAULT_TOPIC_LATEST_POST_DAYS_AGO = 1;
|
||||||
|
protected static final int DEFAULT_MAX_RESULTS = 10;
|
||||||
|
|
||||||
|
protected static final StoreRef SPACES_STORE = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
|
||||||
|
|
||||||
|
protected static final String SEARCH_QUERY = "TYPE:\"{http://www.alfresco.org/model/forum/1.0}post\""
|
||||||
|
+ " AND PATH:\"/app:company_home/st:sites/%s/cm:discussions/*/*\""
|
||||||
|
+ " AND @cm:created:[\"%s\" TO NOW]";
|
||||||
|
|
||||||
|
/** Spring-injected services */
|
||||||
|
private SearchService searchService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the searchService.
|
||||||
|
*
|
||||||
|
* @param searchService SearchService
|
||||||
|
*/
|
||||||
|
public void setSearchService(SearchService searchService)
|
||||||
|
{
|
||||||
|
this.searchService = searchService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides AbstractDiscussionWebScript to allow a null site
|
||||||
|
*
|
||||||
|
* @param req WebScriptRequest
|
||||||
|
* @param status Status
|
||||||
|
* @param cache Cache
|
||||||
|
*
|
||||||
|
* @return Map
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
|
||||||
|
{
|
||||||
|
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
|
||||||
|
if (templateVars == null)
|
||||||
|
{
|
||||||
|
String error = "No parameters supplied";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
SiteInfo site = null;
|
||||||
|
|
||||||
|
if (templateVars.containsKey("site"))
|
||||||
|
{
|
||||||
|
// Site, and optionally topic
|
||||||
|
String siteName = templateVars.get("site");
|
||||||
|
site = siteService.getSite(siteName);
|
||||||
|
if (site == null)
|
||||||
|
{
|
||||||
|
String error = "Could not find site: " + siteName;
|
||||||
|
throw new WebScriptException(Status.STATUS_NOT_FOUND, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Have the real work done
|
||||||
|
return executeImpl(site, null, null, null, req, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param site SiteInfo
|
||||||
|
* @param nodeRef Not required. It is only included because it is overriding the parent class.
|
||||||
|
* @param topic Not required. It is only included because it is overriding the parent class.
|
||||||
|
* @param post Not required. It is only included because it is overriding the parent class.
|
||||||
|
* @param req WebScriptRequest
|
||||||
|
* @param status Not required. It is only included because it is overriding the parent class.
|
||||||
|
* @param cache Not required. It is only included because it is overriding the parent class.
|
||||||
|
*
|
||||||
|
* @return Map
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(SiteInfo site, NodeRef nodeRef, TopicInfo topic,
|
||||||
|
PostInfo post, WebScriptRequest req, JSONObject json, Status status, Cache cache)
|
||||||
|
{
|
||||||
|
// They shouldn't be trying to list of an existing Post or Topic
|
||||||
|
if (topic != null || post != null)
|
||||||
|
{
|
||||||
|
String error = "Can't list Topics inside an existing Topic or Post";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set search filter to users topics or all topics
|
||||||
|
String pAuthor = req.getParameter("topics");
|
||||||
|
String author = DEFAULT_TOPIC_AUTHOR;
|
||||||
|
if (pAuthor != null)
|
||||||
|
{
|
||||||
|
author = pAuthor;
|
||||||
|
}
|
||||||
|
// Set the number of days in the past to search from
|
||||||
|
String pDaysAgo = req.getParameter("history");
|
||||||
|
int daysAgo = DEFAULT_TOPIC_LATEST_POST_DAYS_AGO;
|
||||||
|
if (pDaysAgo != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
daysAgo = Integer.parseInt(pDaysAgo);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e)
|
||||||
|
{
|
||||||
|
//do nothing. history has already been preset to the default value.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the complete search query
|
||||||
|
Pair<String, String> searchQuery = getSearchQuery(site, author, daysAgo);
|
||||||
|
|
||||||
|
// Get the filtered topics
|
||||||
|
PagingRequest paging = buildPagingRequest(req);
|
||||||
|
PagingResults<TopicInfo> topics = doSearch(searchQuery, false, paging);
|
||||||
|
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = buildCommonModel(site, topic, post, req);
|
||||||
|
|
||||||
|
// Have the topics rendered
|
||||||
|
model.put("data", renderTopics(topics, paging, site));
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do the actual search
|
||||||
|
*
|
||||||
|
* @param searchQuery Pair with query string in first and query language in second
|
||||||
|
* @param sortAscending boolean
|
||||||
|
* @param paging PagingRequest
|
||||||
|
*/
|
||||||
|
protected PagingResults<TopicInfo> doSearch(Pair<String, String> searchQuery, boolean sortAscending, PagingRequest paging)
|
||||||
|
{
|
||||||
|
ResultSet resultSet = null;
|
||||||
|
PagingResults<TopicInfo> pagedResults = new EmptyPagingResults<TopicInfo>();
|
||||||
|
|
||||||
|
String sortOn = "@{http://www.alfresco.org/model/content/1.0}created";
|
||||||
|
|
||||||
|
// Setup the search parameters
|
||||||
|
SearchParameters sp = new SearchParameters();
|
||||||
|
sp.addStore(SPACES_STORE);
|
||||||
|
sp.setQuery(searchQuery.getFirst());
|
||||||
|
sp.setLanguage(searchQuery.getSecond());
|
||||||
|
sp.addSort(sortOn, sortAscending);
|
||||||
|
if (paging.getMaxItems() > 0)
|
||||||
|
{
|
||||||
|
//Multiply maxItems by 10. This is to catch topics that have multiple replies and ensure that the maximum number of topics is shown.
|
||||||
|
sp.setLimit(paging.getMaxItems()*10);
|
||||||
|
sp.setLimitBy(LimitBy.FINAL_SIZE);
|
||||||
|
}
|
||||||
|
if (paging.getSkipCount() > 0)
|
||||||
|
{
|
||||||
|
sp.setSkipCount(paging.getSkipCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
resultSet = searchService.query(sp);
|
||||||
|
pagedResults = wrap(resultSet, paging);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
resultSet.close();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pagedResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the search query from the passed in parameters and SEARCH_QUERY constant
|
||||||
|
*
|
||||||
|
* @param site SiteInfo
|
||||||
|
* @param author String
|
||||||
|
* @param daysAgo int
|
||||||
|
* @return Pair with the query string in first and query language in second
|
||||||
|
*/
|
||||||
|
protected Pair<String, String> getSearchQuery(SiteInfo site, String author, int daysAgo)
|
||||||
|
{
|
||||||
|
String search = String.format(SEARCH_QUERY,
|
||||||
|
(site != null ? "cm:" + ISO9075.encode(site.getShortName()) : "*"),
|
||||||
|
getDateXDaysAgo(daysAgo)
|
||||||
|
);
|
||||||
|
|
||||||
|
// If author equals 'mine' add cm:creator to the search query otherwise leave out
|
||||||
|
if(author.equals(DEFAULT_TOPIC_AUTHOR))
|
||||||
|
{
|
||||||
|
search += " AND @cm:creator:\"" + AuthenticationUtil.getFullyAuthenticatedUser() + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the query string and language to the returned results
|
||||||
|
Pair<String, String> searchQuery = new Pair<String, String>(search, SearchService.LANGUAGE_FTS_ALFRESCO);
|
||||||
|
|
||||||
|
return searchQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the date x days ago in the format 'yyyy-MM-dd'
|
||||||
|
*
|
||||||
|
* @param daysAgo int
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
protected String getDateXDaysAgo(int daysAgo)
|
||||||
|
{
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.add(Calendar.DAY_OF_MONTH, (daysAgo * -1));
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
|
||||||
|
return sdf.format(calendar.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds up a listing Paging request, based on the arguments specified in the URL
|
||||||
|
*
|
||||||
|
* @param req WebScriptRequest
|
||||||
|
* @return PagingRequest
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected PagingRequest buildPagingRequest(WebScriptRequest req)
|
||||||
|
{
|
||||||
|
// Grab the number of topics to return
|
||||||
|
String pResultSize = req.getParameter("resultSize");
|
||||||
|
int resultSize = DEFAULT_MAX_RESULTS;
|
||||||
|
if (pResultSize != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
resultSize = Integer.parseInt(pResultSize);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e)
|
||||||
|
{
|
||||||
|
//do nothing. ResultSize has already been preset to the default value.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ScriptPagingDetails(req, resultSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap up search results as {@link TopicInfo} instances
|
||||||
|
*
|
||||||
|
* @param finalResults ResultSet
|
||||||
|
* @param paging PagingRequest
|
||||||
|
*/
|
||||||
|
protected PagingResults<TopicInfo> wrap(final ResultSet finalResults, PagingRequest paging)
|
||||||
|
{
|
||||||
|
int maxItems = paging.getMaxItems();
|
||||||
|
Comparator<TopicInfo> lastPostDesc = new Comparator<TopicInfo>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int compare(TopicInfo t1, TopicInfo t2)
|
||||||
|
{
|
||||||
|
Date t1LastPostDate = t1.getCreatedAt();
|
||||||
|
if(discussionService.getMostRecentPost(t1) != null)
|
||||||
|
{
|
||||||
|
t1LastPostDate = discussionService.getMostRecentPost(t1).getCreatedAt();
|
||||||
|
}
|
||||||
|
|
||||||
|
Date t2LastPostDate = t2.getCreatedAt();
|
||||||
|
if(discussionService.getMostRecentPost(t2) != null)
|
||||||
|
{
|
||||||
|
t2LastPostDate = discussionService.getMostRecentPost(t2).getCreatedAt();
|
||||||
|
}
|
||||||
|
return t2LastPostDate.compareTo(t1LastPostDate);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final Set<TopicInfo> topics = new TreeSet<TopicInfo>(lastPostDesc);
|
||||||
|
|
||||||
|
for (ResultSetRow row : finalResults)
|
||||||
|
{
|
||||||
|
Pair<TopicInfo, PostInfo> pair = discussionService.getForNodeRef(row.getNodeRef());
|
||||||
|
TopicInfo topic = pair.getFirst();
|
||||||
|
if(topic != null)
|
||||||
|
{
|
||||||
|
String path = nodeService.getPath(topic.getNodeRef()).toDisplayPath(nodeService, permissionService);
|
||||||
|
String site = path.split("/")[3];
|
||||||
|
TopicInfoImpl tii = (TopicInfoImpl)topic;
|
||||||
|
tii.setShortSiteName(site);
|
||||||
|
topics.add(tii);
|
||||||
|
|
||||||
|
if(topics.size() >= maxItems)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap
|
||||||
|
return new PagingResults<TopicInfo>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean hasMoreItems()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return finalResults.hasMore();
|
||||||
|
}
|
||||||
|
catch(UnsupportedOperationException e)
|
||||||
|
{
|
||||||
|
// Not all search results support paging
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<Integer, Integer> getTotalResultCount()
|
||||||
|
{
|
||||||
|
int skipCount = 0;
|
||||||
|
int itemsRemainingAfterThisPage = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
skipCount = finalResults.getStart();
|
||||||
|
}
|
||||||
|
catch(UnsupportedOperationException e) {}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
itemsRemainingAfterThisPage = finalResults.length();
|
||||||
|
}
|
||||||
|
catch(UnsupportedOperationException e) {}
|
||||||
|
|
||||||
|
final int totalItemsInUnpagedResultSet = skipCount + itemsRemainingAfterThisPage;
|
||||||
|
return new Pair<Integer, Integer>(totalItemsInUnpagedResultSet, totalItemsInUnpagedResultSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TopicInfo> getPage()
|
||||||
|
{
|
||||||
|
return new ArrayList<TopicInfo>(topics);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getQueryExecutionId()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.query.PagingRequest;
|
||||||
|
import org.alfresco.query.PagingResults;
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.springframework.extensions.surf.util.URLDecoder;
|
||||||
|
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 discussions topics fetching forum-posts.get webscript.
|
||||||
|
*
|
||||||
|
* @author Nick Burch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public class ForumTopicsGet extends AbstractDiscussionWebScript
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(SiteInfo site, NodeRef nodeRef,
|
||||||
|
TopicInfo topic, PostInfo post, WebScriptRequest req, JSONObject json,
|
||||||
|
Status status, Cache cache)
|
||||||
|
{
|
||||||
|
// They shouldn't be trying to list of an existing Post or Topic
|
||||||
|
if (topic != null || post != null)
|
||||||
|
{
|
||||||
|
String error = "Can't list Topics inside an existing Topic or Post";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we need to list or search?
|
||||||
|
boolean tagSearch = false;
|
||||||
|
String tag = req.getParameter("tag");
|
||||||
|
if (tag != null && tag.length() > 0)
|
||||||
|
{
|
||||||
|
tagSearch = true;
|
||||||
|
|
||||||
|
// Tags can be full unicode strings, so decode
|
||||||
|
tag = URLDecoder.decode(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the topics
|
||||||
|
boolean oldestTopicsFirst = false;
|
||||||
|
PagingResults<TopicInfo> topics = null;
|
||||||
|
PagingRequest paging = buildPagingRequest(req);
|
||||||
|
if (tagSearch)
|
||||||
|
{
|
||||||
|
// Tag based is a search rather than a listing
|
||||||
|
if (site != null)
|
||||||
|
{
|
||||||
|
topics = discussionService.findTopics(site.getShortName(), null, tag, oldestTopicsFirst, paging);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
topics = discussionService.findTopics(nodeRef, null, tag, oldestTopicsFirst, paging);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (site != null)
|
||||||
|
{
|
||||||
|
topics = discussionService.listTopics(site.getShortName(), oldestTopicsFirst, paging);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
topics = discussionService.listTopics(nodeRef, oldestTopicsFirst, buildPagingRequest(req));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If they did a site based search, and the component hasn't
|
||||||
|
// been created yet, use the site for the permissions checking
|
||||||
|
if (site != null && nodeRef == null)
|
||||||
|
{
|
||||||
|
nodeRef = site.getNodeRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = buildCommonModel(site, topic, post, req);
|
||||||
|
model.put("forum", nodeRef);
|
||||||
|
|
||||||
|
// Have the topics rendered
|
||||||
|
model.put("data", renderTopics(topics, paging, site));
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.query.PagingRequest;
|
||||||
|
import org.alfresco.query.PagingResults;
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.alfresco.util.Pair;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
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 discussions topics fetching forum-posts-hot.get webscript.
|
||||||
|
*
|
||||||
|
* @author Nick Burch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public class ForumTopicsHotGet extends AbstractDiscussionWebScript
|
||||||
|
{
|
||||||
|
protected static final int RECENT_POSTS_PERIOD_DAYS = 30;
|
||||||
|
protected static final long ONE_DAY_MS = 24*60*60*1000;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(SiteInfo site, NodeRef nodeRef,
|
||||||
|
TopicInfo topic, PostInfo post, WebScriptRequest req, JSONObject json,
|
||||||
|
Status status, Cache cache)
|
||||||
|
{
|
||||||
|
// They shouldn't be trying to list of an existing Post or Topic
|
||||||
|
if (topic != null || post != null)
|
||||||
|
{
|
||||||
|
String error = "Can't list Topics inside an existing Topic or Post";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the date range to search over
|
||||||
|
String numDaysS = req.getParameter("numdays");
|
||||||
|
int numDays = RECENT_POSTS_PERIOD_DAYS;
|
||||||
|
if (numDaysS != null)
|
||||||
|
{
|
||||||
|
numDays = Integer.parseInt(numDaysS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
Date since = new Date(now.getTime() - numDays*ONE_DAY_MS);
|
||||||
|
|
||||||
|
// Get the topics with recent replies
|
||||||
|
PagingResults<Pair<TopicInfo,Integer>> topicsAndCounts = null;
|
||||||
|
PagingRequest paging = buildPagingRequest(req);
|
||||||
|
if (site != null)
|
||||||
|
{
|
||||||
|
topicsAndCounts = discussionService.listHotTopics(site.getShortName(), since, paging);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
topicsAndCounts = discussionService.listHotTopics(nodeRef, since, paging);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For this, we actually only need the topics, not their counts too
|
||||||
|
List<TopicInfo> topics = new ArrayList<TopicInfo>();
|
||||||
|
for (Pair<TopicInfo,Integer> tc : topicsAndCounts.getPage())
|
||||||
|
{
|
||||||
|
topics.add(tc.getFirst());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If they did a site based search, and the component hasn't
|
||||||
|
// been created yet, use the site for the permissions checking
|
||||||
|
if (site != null && nodeRef == null)
|
||||||
|
{
|
||||||
|
nodeRef = site.getNodeRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = buildCommonModel(site, topic, post, req);
|
||||||
|
model.put("forum", nodeRef);
|
||||||
|
|
||||||
|
// Have the topics rendered
|
||||||
|
model.put("data", renderTopics(topics, topicsAndCounts.getTotalResultCount(), paging, site));
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.query.PagingRequest;
|
||||||
|
import org.alfresco.query.PagingResults;
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
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 discussions topics fetching forum-posts-mine.get webscript.
|
||||||
|
*
|
||||||
|
* @author Nick Burch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public class ForumTopicsMineGet extends AbstractDiscussionWebScript
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(SiteInfo site, NodeRef nodeRef,
|
||||||
|
TopicInfo topic, PostInfo post, WebScriptRequest req, JSONObject json,
|
||||||
|
Status status, Cache cache)
|
||||||
|
{
|
||||||
|
// They shouldn't be trying to list of an existing Post or Topic
|
||||||
|
if (topic != null || post != null)
|
||||||
|
{
|
||||||
|
String error = "Can't list Topics inside an existing Topic or Post";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the current user to list for
|
||||||
|
String username = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||||
|
|
||||||
|
// Get the topics for the user, oldest first
|
||||||
|
PagingResults<TopicInfo> topics = null;
|
||||||
|
PagingRequest paging = buildPagingRequest(req);
|
||||||
|
if (site != null)
|
||||||
|
{
|
||||||
|
topics = discussionService.listTopics(site.getShortName(), username, true, paging);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
topics = discussionService.listTopics(nodeRef, username, true, paging);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If they did a site based search, and the component hasn't
|
||||||
|
// been created yet, use the site for the permissions checking
|
||||||
|
if (site != null && nodeRef == null)
|
||||||
|
{
|
||||||
|
nodeRef = site.getNodeRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = buildCommonModel(site, topic, post, req);
|
||||||
|
model.put("forum", nodeRef);
|
||||||
|
|
||||||
|
// Have the topics rendered
|
||||||
|
model.put("data", renderTopics(topics, paging, site));
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Remote API
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.web.scripts.discussion;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.query.PagingRequest;
|
||||||
|
import org.alfresco.query.PagingResults;
|
||||||
|
import org.alfresco.service.cmr.discussion.PostInfo;
|
||||||
|
import org.alfresco.service.cmr.discussion.TopicInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.site.SiteInfo;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
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 discussions topics fetching forum-posts-new.get webscript.
|
||||||
|
*
|
||||||
|
* @author Nick Burch
|
||||||
|
* @since 4.0
|
||||||
|
*/
|
||||||
|
public class ForumTopicsRecentGet extends AbstractDiscussionWebScript
|
||||||
|
{
|
||||||
|
protected static final int RECENT_SEARCH_PERIOD_DAYS = 7;
|
||||||
|
protected static final long ONE_DAY_MS = 24*60*60*1000;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, Object> executeImpl(SiteInfo site, NodeRef nodeRef,
|
||||||
|
TopicInfo topic, PostInfo post, WebScriptRequest req, JSONObject json,
|
||||||
|
Status status, Cache cache)
|
||||||
|
{
|
||||||
|
// They shouldn't be trying to list of an existing Post or Topic
|
||||||
|
if (topic != null || post != null)
|
||||||
|
{
|
||||||
|
String error = "Can't list Topics inside an existing Topic or Post";
|
||||||
|
throw new WebScriptException(Status.STATUS_BAD_REQUEST, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the date range to search over
|
||||||
|
String numDaysS = req.getParameter("numdays");
|
||||||
|
int numDays = RECENT_SEARCH_PERIOD_DAYS;
|
||||||
|
if (numDaysS != null)
|
||||||
|
{
|
||||||
|
numDays = Integer.parseInt(numDaysS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
Date from = new Date(now.getTime() - numDays*ONE_DAY_MS);
|
||||||
|
Date to = new Date(now.getTime() + ONE_DAY_MS);
|
||||||
|
|
||||||
|
// Get the recent topics, newest first
|
||||||
|
PagingResults<TopicInfo> topics = null;
|
||||||
|
PagingRequest paging = buildPagingRequest(req);
|
||||||
|
if (site != null)
|
||||||
|
{
|
||||||
|
topics = discussionService.listTopics(site.getShortName(), from, to, false, paging);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
topics = discussionService.listTopics(nodeRef, from, to, false, paging);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If they did a site based search, and the component hasn't
|
||||||
|
// been created yet, use the site for the permissions checking
|
||||||
|
if (site != null && nodeRef == null)
|
||||||
|
{
|
||||||
|
nodeRef = site.getNodeRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Build the common model parts
|
||||||
|
Map<String, Object> model = buildCommonModel(site, topic, post, req);
|
||||||
|
model.put("forum", nodeRef);
|
||||||
|
|
||||||
|
// Have the topics rendered
|
||||||
|
model.put("data", renderTopics(topics, paging, site));
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
}
|
@@ -26,6 +26,7 @@
|
|||||||
package org.alfresco.rest.api.impl;
|
package org.alfresco.rest.api.impl;
|
||||||
|
|
||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -57,9 +58,11 @@ import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
|||||||
import org.alfresco.rest.framework.resource.parameters.Paging;
|
import org.alfresco.rest.framework.resource.parameters.Paging;
|
||||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||||
import org.alfresco.rest.framework.resource.parameters.Params;
|
import org.alfresco.rest.framework.resource.parameters.Params;
|
||||||
|
import org.alfresco.rest.framework.resource.parameters.SortColumn;
|
||||||
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
|
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
|
||||||
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper.WalkerCallbackAdapter;
|
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper.WalkerCallbackAdapter;
|
||||||
import org.alfresco.service.cmr.favourites.FavouritesService;
|
import org.alfresco.service.cmr.favourites.FavouritesService;
|
||||||
|
import org.alfresco.service.cmr.favourites.FavouritesService.SortFields;
|
||||||
import org.alfresco.service.cmr.favourites.FavouritesService.Type;
|
import org.alfresco.service.cmr.favourites.FavouritesService.Type;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
@@ -308,6 +311,8 @@ public class FavouritesImpl implements Favourites
|
|||||||
|
|
||||||
Paging paging = parameters.getPaging();
|
Paging paging = parameters.getPaging();
|
||||||
|
|
||||||
|
List<Pair<FavouritesService.SortFields, Boolean>> sortProps = getSortProps(parameters);
|
||||||
|
|
||||||
final Set<Type> filteredByClientQuery = new HashSet<Type>();
|
final Set<Type> filteredByClientQuery = new HashSet<Type>();
|
||||||
Set<Type> filterTypes = FavouritesService.Type.ALL_FILTER_TYPES; //Default all
|
Set<Type> filterTypes = FavouritesService.Type.ALL_FILTER_TYPES; //Default all
|
||||||
|
|
||||||
@@ -345,8 +350,8 @@ public class FavouritesImpl implements Favourites
|
|||||||
filterTypes = filteredByClientQuery;
|
filterTypes = filteredByClientQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
final PagingResults<PersonFavourite> favourites = favouritesService.getPagedFavourites(personId, filterTypes, FavouritesService.DEFAULT_SORT_PROPS,
|
final PagingResults<PersonFavourite> favourites = favouritesService.getPagedFavourites(personId, filterTypes, sortProps, Util.getPagingRequest(paging));
|
||||||
Util.getPagingRequest(paging));
|
|
||||||
return wrap(paging, favourites, parameters);
|
return wrap(paging, favourites, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,4 +375,32 @@ public class FavouritesImpl implements Favourites
|
|||||||
Parameters parameters = Params.valueOf(recognizedParams, personId, favouriteId, null);
|
Parameters parameters = Params.valueOf(recognizedParams, personId, favouriteId, null);
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Pair<FavouritesService.SortFields, Boolean>> getSortProps(Parameters parameters)
|
||||||
|
{
|
||||||
|
List<Pair<FavouritesService.SortFields, Boolean>> sortProps = new ArrayList<>();
|
||||||
|
List<SortColumn> sortCols = parameters.getSorting();
|
||||||
|
if ((sortCols != null) && (sortCols.size() > 0))
|
||||||
|
{
|
||||||
|
for (SortColumn sortCol : sortCols)
|
||||||
|
{
|
||||||
|
SortFields sortField;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sortField = SortFields.valueOf(sortCol.column);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new InvalidArgumentException("Invalid sort field: " + sortCol.column);
|
||||||
|
}
|
||||||
|
sortProps.add(new Pair<>(sortField, (sortCol.asc ? Boolean.TRUE : Boolean.FALSE)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// default sort order
|
||||||
|
sortProps = FavouritesService.DEFAULT_SORT_PROPS;
|
||||||
|
}
|
||||||
|
return sortProps;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -328,6 +328,15 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="discussionsActivitySummaryProcessor" class="org.alfresco.rest.api.impl.activities.DiscussionsActivitySummaryProcessor">
|
||||||
|
<property name="registry" ref="activitySummaryParser" />
|
||||||
|
<property name="eventTypes">
|
||||||
|
<list>
|
||||||
|
<value>org.alfresco.discussions.reply-created</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
<bean id="subscriptionsActivitySummaryProcessor" class="org.alfresco.rest.api.impl.activities.SubscriptionsActivitySummaryProcessor">
|
<bean id="subscriptionsActivitySummaryProcessor" class="org.alfresco.rest.api.impl.activities.SubscriptionsActivitySummaryProcessor">
|
||||||
<property name="registry" ref="activitySummaryParser" />
|
<property name="registry" ref="activitySummaryParser" />
|
||||||
<property name="eventTypes">
|
<property name="eventTypes">
|
||||||
|
@@ -0,0 +1,14 @@
|
|||||||
|
<#include "../slingshot-common.lib.ftl">
|
||||||
|
<entry xmlns='http://www.w3.org/2005/Atom'>
|
||||||
|
<title>New discussion: ${htmlTitle?xml}</title>
|
||||||
|
<link rel="alternate" type="text/html" href="" />
|
||||||
|
<id>http://www.alfresco.org/rss/atom/${id}</id>
|
||||||
|
<updated>${xmldate(date)}</updated>
|
||||||
|
<summary type="html">
|
||||||
|
<![CDATA["${htmlTitle}" discussion created by ${userName?html}.]]>
|
||||||
|
</summary>
|
||||||
|
<author>
|
||||||
|
<name>${userName?xml}</name>
|
||||||
|
<uri>${userId?xml}</uri>
|
||||||
|
</author>
|
||||||
|
</entry>
|
@@ -0,0 +1,14 @@
|
|||||||
|
<#include "../slingshot-common.lib.ftl">
|
||||||
|
<entry xmlns='http://www.w3.org/2005/Atom'>
|
||||||
|
<title>Discussion deleted: ${htmlTitle?xml}</title>
|
||||||
|
<link rel="alternate" type="text/html" href="" />
|
||||||
|
<id>http://www.alfresco.org/rss/atom/${id}</id>
|
||||||
|
<updated>${xmldate(date)}</updated>
|
||||||
|
<summary type="html">
|
||||||
|
<![CDATA["${htmlTitle}" discussion deleted by ${userName?html}.]]>
|
||||||
|
</summary>
|
||||||
|
<author>
|
||||||
|
<name>${userName?xml}</name>
|
||||||
|
<uri>${userId?xml}</uri>
|
||||||
|
</author>
|
||||||
|
</entry>
|
@@ -0,0 +1,14 @@
|
|||||||
|
<#include "../slingshot-common.lib.ftl">
|
||||||
|
<entry xmlns='http://www.w3.org/2005/Atom'>
|
||||||
|
<title>Discussion updated: ${htmlTitle?xml}</title>
|
||||||
|
<link rel="alternate" type="text/html" href="" />
|
||||||
|
<id>http://www.alfresco.org/rss/atom/${id}</id>
|
||||||
|
<updated>${xmldate(date)}</updated>
|
||||||
|
<summary type="html">
|
||||||
|
<![CDATA["${htmlTitle}" discussion updated by ${userName?html}.]]>
|
||||||
|
</summary>
|
||||||
|
<author>
|
||||||
|
<name>${userName?xml}</name>
|
||||||
|
<uri>${userId?xml}</uri>
|
||||||
|
</author>
|
||||||
|
</entry>
|
@@ -0,0 +1,14 @@
|
|||||||
|
<#include "../slingshot-common.lib.ftl">
|
||||||
|
<entry xmlns='http://www.w3.org/2005/Atom'>
|
||||||
|
<title>Reply added to ${(htmlTitle!'')?html?xml}</title>
|
||||||
|
<link rel="alternate" type="text/html" href="" />
|
||||||
|
<id>http://www.alfresco.org/rss/atom/${id}</id>
|
||||||
|
<updated>${xmldate(date)}</updated>
|
||||||
|
<summary type="html">
|
||||||
|
<![CDATA["${htmlTitle}" replied to by ${userName?html}.]]>
|
||||||
|
</summary>
|
||||||
|
<author>
|
||||||
|
<name>${userName?xml}</name>
|
||||||
|
<uri>${userId?xml}</uri>
|
||||||
|
</author>
|
||||||
|
</entry>
|
@@ -0,0 +1,14 @@
|
|||||||
|
<#include "../slingshot-common.lib.ftl">
|
||||||
|
<entry xmlns='http://www.w3.org/2005/Atom'>
|
||||||
|
<title>Reply to ${(htmlTitle!'')?html?xml} updated</title>
|
||||||
|
<link rel="alternate" type="text/html" href="" />
|
||||||
|
<id>http://www.alfresco.org/rss/atom/${id}</id>
|
||||||
|
<updated>${xmldate(date)}</updated>
|
||||||
|
<summary type="html">
|
||||||
|
<![CDATA[Reply to "${htmlTitle}" updated by ${userName?html}.]]>
|
||||||
|
</summary>
|
||||||
|
<author>
|
||||||
|
<name>${userName?xml}</name>
|
||||||
|
<uri>${userId?xml}</uri>
|
||||||
|
</author>
|
||||||
|
</entry>
|
@@ -1,9 +0,0 @@
|
|||||||
<webscript>
|
|
||||||
<shortname>Retrieve Event Defaults</shortname>
|
|
||||||
<description>Retrieve Event Defaults</description>
|
|
||||||
<url>/calendar/RetrieveEventDefaults?s={spaceRef}</url>
|
|
||||||
<format default="html">extension</format>
|
|
||||||
<authentication>user</authentication>
|
|
||||||
<transaction allow="readonly">required</transaction>
|
|
||||||
<lifecycle>internal</lifecycle>
|
|
||||||
</webscript>
|
|
@@ -1 +0,0 @@
|
|||||||
${result}
|
|
@@ -1,54 +0,0 @@
|
|||||||
function getGUIDFromNodeRef(nodeRef)
|
|
||||||
{
|
|
||||||
var str = "" + nodeRef;
|
|
||||||
return str.substring(str.lastIndexOf("/")+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function findNodeByNodeRef(nodeRef)
|
|
||||||
{
|
|
||||||
var resultsArray= search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef));
|
|
||||||
|
|
||||||
if (resultsArray != null && resultsArray.length > 0)
|
|
||||||
{
|
|
||||||
return resultsArray[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var spaceRef = args.s;
|
|
||||||
var currentBaseSpace = findNodeByNodeRef(spaceRef);
|
|
||||||
var response = ""
|
|
||||||
var _today = new Date();
|
|
||||||
|
|
||||||
if (currentBaseSpace != null)
|
|
||||||
{
|
|
||||||
if (currentBaseSpace.properties["ia:whatEventDefault"] != null)
|
|
||||||
response += currentBaseSpace.properties["ia:whatEventDefault"] + "^";
|
|
||||||
else
|
|
||||||
response += "" + "^";
|
|
||||||
|
|
||||||
if (currentBaseSpace.properties["ia:fromDateDefault"] != null)
|
|
||||||
response += currentBaseSpace.properties["ia:fromDateDefault"] + "^";
|
|
||||||
else
|
|
||||||
response += _today.toString() + "^";
|
|
||||||
|
|
||||||
if (currentBaseSpace.properties["ia:toDateDefault"] != null)
|
|
||||||
response += currentBaseSpace.properties["ia:toDateDefault"] + "^";
|
|
||||||
else
|
|
||||||
response += _today.toString() + "^";
|
|
||||||
|
|
||||||
if (currentBaseSpace.properties["ia:whereEventDefault"] != null)
|
|
||||||
response += currentBaseSpace.properties["ia:whereEventDefault"] + "^";
|
|
||||||
else
|
|
||||||
response += "" + "^";
|
|
||||||
|
|
||||||
if (currentBaseSpace.properties["ia:colorEventDefault"] != null)
|
|
||||||
response += currentBaseSpace.properties["ia:colorEventDefault"];
|
|
||||||
else
|
|
||||||
response += "";
|
|
||||||
}
|
|
||||||
logger.log("RESPONSE: " + response);
|
|
||||||
model.result = response;
|
|
@@ -1,9 +0,0 @@
|
|||||||
<webscript>
|
|
||||||
<shortname>Retrieve Event Details</shortname>
|
|
||||||
<description>Retrieve Event Details</description>
|
|
||||||
<url>/calendar/RetrieveEventDetails?e={eventId}</url>
|
|
||||||
<format default="html">extension</format>
|
|
||||||
<authentication>user</authentication>
|
|
||||||
<transaction allow="readonly">required</transaction>
|
|
||||||
<lifecycle>internal</lifecycle>
|
|
||||||
</webscript>
|
|
@@ -1 +0,0 @@
|
|||||||
${result}
|
|
@@ -1,35 +0,0 @@
|
|||||||
var eventId = args.e;
|
|
||||||
var eventNode = search.findNode(eventId);
|
|
||||||
|
|
||||||
if (eventNode == null)
|
|
||||||
{
|
|
||||||
model.result = "Event not Found";
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var response = "";
|
|
||||||
var _fromDate = eventNode.properties["ia:fromDate"];
|
|
||||||
var _toDate = eventNode.properties["ia:toDate"];
|
|
||||||
var _fromMonth = _fromDate.getMonth() + 1;
|
|
||||||
var _toMonth = _toDate.getMonth() + 1;
|
|
||||||
|
|
||||||
response += eventNode.properties["ia:whatEvent"] + "^";
|
|
||||||
response += _fromMonth + "/" + _fromDate.getDate() + "/" + _fromDate.getFullYear() + "^";
|
|
||||||
var frmHour = _fromDate.getHours();
|
|
||||||
if (frmHour == 0) frmHour += "0";
|
|
||||||
var frmMin = _fromDate.getMinutes();
|
|
||||||
if (frmMin == 0) frmMin += "0";
|
|
||||||
response += frmHour + ":" + frmMin + "^";
|
|
||||||
response += _toMonth + "/" + _toDate.getDate() + "/" + _toDate.getFullYear() + "^";
|
|
||||||
var toHour = _toDate.getHours();
|
|
||||||
if (toHour == 0) toHour += "0";
|
|
||||||
var toMin = _toDate.getMinutes();
|
|
||||||
if (toMin == 0) toMin += "0";
|
|
||||||
response += toHour + ":" + toMin + "^";
|
|
||||||
response += eventNode.properties["ia:whereEvent"] + "^";
|
|
||||||
response += eventNode.properties["ia:descriptionEvent"] + "^";
|
|
||||||
response += eventNode.properties["ia:colorEvent"];
|
|
||||||
|
|
||||||
model.result=response;
|
|
||||||
}
|
|
@@ -1,9 +0,0 @@
|
|||||||
<webscript>
|
|
||||||
<shortname>Save Calendar Event</shortname>
|
|
||||||
<description>Save Calendar Event</description>
|
|
||||||
<url>/calendar/SaveCalendarEvent?what={whatEvent}&where={whereEvent}&desc={descriptionEvent}&color={colorEvent}&fd={fromDate}&ft={fromTime}&td={toDate}&tt={toTime}&e={eventId}&d={toDelete}&s={spaceRef}</url>
|
|
||||||
<format default="html">extension</format>
|
|
||||||
<authentication>user</authentication>
|
|
||||||
<transaction>required</transaction>
|
|
||||||
<lifecycle>internal</lifecycle>
|
|
||||||
</webscript>
|
|
@@ -1 +0,0 @@
|
|||||||
${result}
|
|
@@ -1,103 +0,0 @@
|
|||||||
var now = new Date();
|
|
||||||
var day = now.getDay();
|
|
||||||
var month = now.getMonth();
|
|
||||||
var year = now.getYear();
|
|
||||||
var hour = now.getHours();
|
|
||||||
var minute = now.getMinutes();
|
|
||||||
var second = now.getSeconds();
|
|
||||||
|
|
||||||
var stamp = day + month + year + hour.toString() + minute + second;
|
|
||||||
logger.log("DATE: " + args.fd + " " + args.ft);
|
|
||||||
var fromDateString = args.fd + " " + args.ft;
|
|
||||||
var fromDateDate = new Date(fromDateString);
|
|
||||||
|
|
||||||
var toDateString = args.td + " " + args.tt;
|
|
||||||
var toDateDate = new Date(toDateString);
|
|
||||||
|
|
||||||
var content = "What: " + args.what + "<BR>";
|
|
||||||
content += "When: " + args.fd + " " + args.ft + " to " + args.td + " " + args.tt + "<BR>";
|
|
||||||
content += "Where: " + args.where + "<BR>";
|
|
||||||
content += "Description: " + args.desc + "<BR>";
|
|
||||||
content += "Color: " + args.color;
|
|
||||||
|
|
||||||
var fileNode = null;
|
|
||||||
var eventId = args.e;
|
|
||||||
var toDelete = args.d;
|
|
||||||
|
|
||||||
var spaceRef = args.s;
|
|
||||||
var nodeWhereToCreate = findNodeByNodeRef(spaceRef);
|
|
||||||
|
|
||||||
var response;
|
|
||||||
|
|
||||||
if (nodeWhereToCreate != null)
|
|
||||||
{
|
|
||||||
var newFolder = nodeWhereToCreate.childByNamePath("CalEvents");
|
|
||||||
if (newFolder == null)
|
|
||||||
nodeWhereToCreate = nodeWhereToCreate.createFolder("CalEvents");
|
|
||||||
else
|
|
||||||
nodeWhereToCreate = newFolder;
|
|
||||||
|
|
||||||
if (eventId == null)
|
|
||||||
{
|
|
||||||
fileNode = nodeWhereToCreate.createNode(stamp + ".ics", "ia:calendarEvent");
|
|
||||||
saveNodeDetails();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fileNode = search.findNode(eventId);
|
|
||||||
if (toDelete == 'true')
|
|
||||||
{
|
|
||||||
var status = fileNode.remove();
|
|
||||||
if (status)
|
|
||||||
response = "DELETED";
|
|
||||||
else
|
|
||||||
response = "NOT DELETED";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
saveNodeDetails();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response = "SPACE not found";
|
|
||||||
}
|
|
||||||
|
|
||||||
model.result = response;
|
|
||||||
|
|
||||||
|
|
||||||
function saveNodeDetails()
|
|
||||||
{
|
|
||||||
fileNode.properties["ia:whatEvent"] = args.what;
|
|
||||||
fileNode.properties["ia:fromDate"] = fromDateDate;
|
|
||||||
fileNode.properties["ia:toDate"] = toDateDate;
|
|
||||||
fileNode.properties["ia:whereEvent"] = args.where;
|
|
||||||
fileNode.properties["ia:descriptionEvent"] = args.desc;
|
|
||||||
fileNode.properties["ia:colorEvent"] = args.color;
|
|
||||||
|
|
||||||
fileNode.save();
|
|
||||||
fileNode.content = content;
|
|
||||||
|
|
||||||
response = fileNode.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGUIDFromNodeRef(nodeRef)
|
|
||||||
{
|
|
||||||
var str = "" + nodeRef;
|
|
||||||
return str.substring(str.lastIndexOf("/")+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function findNodeByNodeRef(nodeRef)
|
|
||||||
{
|
|
||||||
var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef));
|
|
||||||
|
|
||||||
if (resultsArray != null && resultsArray.length > 0)
|
|
||||||
{
|
|
||||||
return resultsArray[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,7 +0,0 @@
|
|||||||
<webscript>
|
|
||||||
<shortname>Calendar Subscriptions</shortname>
|
|
||||||
<description>Calendar Subscriptions</description>
|
|
||||||
<url>/calendar/calendarRemove</url>
|
|
||||||
<authentication>user</authentication>
|
|
||||||
<lifecycle>internal</lifecycle>
|
|
||||||
</webscript>
|
|
@@ -1,6 +0,0 @@
|
|||||||
<select id="subscriptions" style="width:300px" size="8" multiple="multiple">
|
|
||||||
<#list resultset as node>
|
|
||||||
<option value="${node.nodeRef}">${node.parent.name}</option>
|
|
||||||
</#list>
|
|
||||||
</select>
|
|
||||||
|
|
@@ -1,33 +0,0 @@
|
|||||||
function getGUIDFromNodeRef(nodeRef) {
|
|
||||||
var str = "" + nodeRef;
|
|
||||||
if (str.length > 24) {
|
|
||||||
return str.substring(24);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findNodeByNodeRef(nodeRef) {
|
|
||||||
var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef));
|
|
||||||
if (resultsArray != null && resultsArray.length > 0) {
|
|
||||||
return resultsArray[0];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var spaceRef = args.ref;
|
|
||||||
var space = findNodeByNodeRef(spaceRef);
|
|
||||||
|
|
||||||
// Resolve the calendar reference
|
|
||||||
var calendar = findNodeByNodeRef(args.calendar);
|
|
||||||
if (calendar != null) {
|
|
||||||
space.removeAssociation(calendar, "ia:subscribedCalendarList");
|
|
||||||
space.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
var calendars = space.assocs["ia:subscribedCalendarList"];
|
|
||||||
if (calendars == null) {
|
|
||||||
calendars = new Array();
|
|
||||||
}
|
|
||||||
model.resultset = calendars;
|
|
@@ -1,8 +0,0 @@
|
|||||||
<webscript>
|
|
||||||
<shortname>Calendar Events</shortname>
|
|
||||||
<description>Calendar Events</description>
|
|
||||||
<url>/calendar/getCalendarEvents</url>
|
|
||||||
<authentication>user</authentication>
|
|
||||||
<transaction allow="readonly">required</transaction>
|
|
||||||
<lifecycle>internal</lifecycle>
|
|
||||||
</webscript>
|
|
@@ -1,20 +0,0 @@
|
|||||||
<script type="text/javascript" src="${url.context}/yui/build/yahoo/yahoo.js"></script>
|
|
||||||
<script type="text/javascript" src="${url.context}/yui/build/event/event.js" ></script>
|
|
||||||
<script type="text/javascript" src="${url.context}/yui/build/dom/dom.js" ></script>
|
|
||||||
<script type="text/javascript" src="${url.context}/yui/build/calendar/calendar.js"></script>
|
|
||||||
<link type="text/css" rel="stylesheet" href="${url.context}/yui/build/calendar/assets/calendar.css">
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
YAHOO.namespace("example.calendar");
|
|
||||||
YAHOO.example.calendar.init = function() {
|
|
||||||
YAHOO.example.calendar.cal1 = new YAHOO.widget.Calendar("cal1","cal1Container", { pagedate:"${month}/${year}" } );
|
|
||||||
<#list dates as d>
|
|
||||||
YAHOO.example.calendar.cal1.addRenderer("${d}", YAHOO.example.calendar.cal1.renderCellStyleSelected);
|
|
||||||
</#list>
|
|
||||||
YAHOO.example.calendar.cal1.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
YAHOO.util.Event.onDOMReady(YAHOO.example.calendar.init);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="cal1Container"></div>
|
|
@@ -1,87 +0,0 @@
|
|||||||
function getGUIDFromNodeRef(nodeRef) {
|
|
||||||
var str = "" + nodeRef;
|
|
||||||
if (str.length > 24) {
|
|
||||||
return str.substring(24);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findNodeByNodeRef(nodeRef) {
|
|
||||||
var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef));
|
|
||||||
if (resultsArray != null && resultsArray.length > 0) {
|
|
||||||
return resultsArray[0];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var spaceRef = args.ref;
|
|
||||||
var calendar = findNodeByNodeRef(spaceRef);
|
|
||||||
|
|
||||||
function formatANSI(datestr) {
|
|
||||||
var tmp = datestr.split("/");
|
|
||||||
var d = new Date();
|
|
||||||
d.setFullYear(tmp[0]);
|
|
||||||
d.setMonth(tmp[1]-1);
|
|
||||||
d.setDate(tmp[2]);
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Interval(start, end) {
|
|
||||||
this.start = start;
|
|
||||||
this.end = end;
|
|
||||||
};
|
|
||||||
|
|
||||||
Interval.prototype.overlaps = function(interval) {
|
|
||||||
// take the interval with the early start time as the one to compare against
|
|
||||||
var x, y;
|
|
||||||
if (this.start.getTime() < interval.start.getTime()) {
|
|
||||||
x = this; y = interval;
|
|
||||||
} else {
|
|
||||||
x = interval; y = this;
|
|
||||||
}
|
|
||||||
var time = y.start.getTime();
|
|
||||||
return (x.start.getTime() <= time) && (time < this.end.getTime());
|
|
||||||
};
|
|
||||||
|
|
||||||
function isLeap(year) {
|
|
||||||
return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
var monthToDays = [31,28,31,30,31,30,31,31,30,31,30,31];
|
|
||||||
|
|
||||||
if (isLeap(args.year)) {
|
|
||||||
monthToDays[1] = 29; // one extra day in February
|
|
||||||
}
|
|
||||||
|
|
||||||
var fromDate = args.year + "/0" + args.month + "/01";
|
|
||||||
var from = formatANSI(fromDate);
|
|
||||||
var toDate = args.year + "/0" + args.month + "/" + monthToDays[args.month - 1];
|
|
||||||
var to = formatANSI(toDate);
|
|
||||||
var time = new Interval(from, to);
|
|
||||||
|
|
||||||
var selectedDates = new Array();
|
|
||||||
var events = calendar.children;
|
|
||||||
|
|
||||||
for(var i=0; i < events.length; i++) {
|
|
||||||
var event = events[i];
|
|
||||||
var startdate = new Date(event.properties["ia:fromDate"]);
|
|
||||||
var enddate = new Date(event.properties["ia:toDate"]);
|
|
||||||
var interval = new Interval(startdate, enddate);
|
|
||||||
if (interval.overlaps(time)) {
|
|
||||||
var key = (interval.start.getMonth()+1) + "/" + interval.start.getDate();
|
|
||||||
if (selectedDates.indexOf(key) < 0) {
|
|
||||||
selectedDates.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
model.dates = selectedDates;
|
|
||||||
|
|
||||||
// These are only used for the html view
|
|
||||||
model.month = args.month;
|
|
||||||
model.year = args.year;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
results: [<#list dates as d>"${d}"<#if d_has_next>,</#if></#list>]
|
|
||||||
}
|
|
@@ -1,7 +0,0 @@
|
|||||||
<webscript>
|
|
||||||
<shortname>Calendar Subscriptions</shortname>
|
|
||||||
<description>Calendar Subscriptions</description>
|
|
||||||
<url>/calendar/calendarInit</url>
|
|
||||||
<authentication>user</authentication>
|
|
||||||
<lifecycle>internal</lifecycle>
|
|
||||||
</webscript>
|
|
@@ -1,54 +0,0 @@
|
|||||||
<div>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<div id="color2" style="height: 30px; width: 30px; background: ${color}; border: 1px solid black;"> </div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<A HREF="#" onClick="picker.show('pick2');return false;" NAME="pick2" ID="pick2">Select a color</A>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<#-- This MUST be present -->
|
|
||||||
<DIV ID="colorPickerDiv" STYLE=\"position: absolute; left: 0px; top: 0px; z-index: 1; display:none;"> </DIV>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>Available Calendars</td>
|
|
||||||
<td> </td>
|
|
||||||
<td>Subscribed Calendars</td>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td id="availableCalendars">
|
|
||||||
<#-- Display the list of available calendars-->
|
|
||||||
<select id="availcals" style="width:300px" size="8">
|
|
||||||
<#list available as node>
|
|
||||||
<option value="${node.nodeRef}">${node.parent.name}</option>
|
|
||||||
</#list>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<td>
|
|
||||||
<!-- middle column -->
|
|
||||||
<input class="alignMiddle" type="button" onclick="setupCalendarSubscription()" value=">>"/>
|
|
||||||
</td>
|
|
||||||
<td id="subscribedCalendars">
|
|
||||||
<#-- Display the list of subscribed calendars-->
|
|
||||||
<select id="subscriptions" style="width:300px" size="8">
|
|
||||||
<#list subscriptions as node>
|
|
||||||
<option value="${node.nodeRef}">${node.parent.name}</option>
|
|
||||||
</#list>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><input type="text" id="filter" value="" size="25"/><input type="button" onclick="applyFilter(document.getElementById('filter').value);" value="Filter"/></td>
|
|
||||||
<td> </td>
|
|
||||||
<td><input type="button" onclick="removeCalendarSubscription();" value="Remove"/></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
@@ -1,53 +0,0 @@
|
|||||||
function getGUIDFromNodeRef(nodeRef) {
|
|
||||||
var str = "" + nodeRef;
|
|
||||||
if (str.length > 24) {
|
|
||||||
return str.substring(24);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findNodeByNodeRef(nodeRef) {
|
|
||||||
var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef));
|
|
||||||
if (resultsArray != null && resultsArray.length > 0) {
|
|
||||||
return resultsArray[0];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var spaceRef = args.ref;
|
|
||||||
var calendar = findNodeByNodeRef(spaceRef);
|
|
||||||
|
|
||||||
var color = calendar.properties["ia:colorEventDefault"];
|
|
||||||
if (color == null || color.length == 0) {
|
|
||||||
color = "#FF0000"; // default
|
|
||||||
}
|
|
||||||
model.color = color;
|
|
||||||
|
|
||||||
// Get the list of calendars the user is subscribed to
|
|
||||||
var subscriptions = calendar.assocs["ia:subscribedCalendarList"]
|
|
||||||
if (subscriptions == null) {
|
|
||||||
subscriptions = new Array();
|
|
||||||
}
|
|
||||||
model.subscriptions = subscriptions;
|
|
||||||
|
|
||||||
// perform search
|
|
||||||
var nodes = search.luceneSearch('TYPE:\"{http\://www.alfresco.org/model/calendar}calendar\"');
|
|
||||||
|
|
||||||
/**
|
|
||||||
var filtered = new Array();
|
|
||||||
if (nodes.length > 0) {
|
|
||||||
var re = new RegExp(args.q,"i");
|
|
||||||
var j = 0;
|
|
||||||
for(i=0; i < nodes.length; i++) {
|
|
||||||
var n = nodes[i];
|
|
||||||
if (re.test(n.parent.name)) {
|
|
||||||
filtered[j] = n;
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
**/
|
|
||||||
|
|
||||||
model.available = nodes;
|
|
@@ -1,7 +0,0 @@
|
|||||||
<webscript>
|
|
||||||
<shortname>Calendar Subscriptions</shortname>
|
|
||||||
<description>Calendar Subscriptions</description>
|
|
||||||
<url>/calendar/calendarSubscriptions</url>
|
|
||||||
<authentication>user</authentication>
|
|
||||||
<lifecycle>internal</lifecycle>
|
|
||||||
</webscript>
|
|
@@ -1,6 +0,0 @@
|
|||||||
<select id="subscriptions" style="width:300px" size="8" multiple="multiple">
|
|
||||||
<#list resultset as node>
|
|
||||||
<option value="${node.nodeRef}">${node.parent.name}</option>
|
|
||||||
</#list>
|
|
||||||
</select>
|
|
||||||
|
|
@@ -1,29 +0,0 @@
|
|||||||
function getGUIDFromNodeRef(nodeRef) {
|
|
||||||
var str = "" + nodeRef;
|
|
||||||
if (str.length > 24) {
|
|
||||||
return str.substring(24);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findNodeByNodeRef(nodeRef) {
|
|
||||||
var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef));
|
|
||||||
if (resultsArray != null && resultsArray.length > 0) {
|
|
||||||
return resultsArray[0];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var spaceRef = args.ref;
|
|
||||||
var space = findNodeByNodeRef(spaceRef);
|
|
||||||
// Resolve the calendar reference
|
|
||||||
var calendar = findNodeByNodeRef(args.calendar);
|
|
||||||
if (calendar != null) {
|
|
||||||
space.createAssociation(calendar, "ia:subscribedCalendarList");
|
|
||||||
space.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
var calendars = space.assocs["ia:subscribedCalendarList"];
|
|
||||||
model.resultset = calendars;
|
|
@@ -1,8 +0,0 @@
|
|||||||
<webscript>
|
|
||||||
<shortname>Calendar Subscriptions</shortname>
|
|
||||||
<description>Calendar Subscriptions</description>
|
|
||||||
<url>/calendar/getColor</url>
|
|
||||||
<authentication>user</authentication>
|
|
||||||
<transaction allow="readonly">required</transaction>
|
|
||||||
<lifecycle>internal</lifecycle>
|
|
||||||
</webscript>
|
|
@@ -1,3 +0,0 @@
|
|||||||
${color}
|
|
||||||
|
|
||||||
|
|
@@ -1,31 +0,0 @@
|
|||||||
function getGUIDFromNodeRef(nodeRef) {
|
|
||||||
var str = "" + nodeRef;
|
|
||||||
if (str.length > 24) {
|
|
||||||
return str.substring(24);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findNodeByNodeRef(nodeRef) {
|
|
||||||
var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef));
|
|
||||||
if (resultsArray != null && resultsArray.length > 0) {
|
|
||||||
return resultsArray[0];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var spaceRef = args.ref;
|
|
||||||
var color = null;
|
|
||||||
var calendar = findNodeByNodeRef(spaceRef);
|
|
||||||
|
|
||||||
if (calendar != null) {
|
|
||||||
color = calendar.properties["ia:colorEventDefault"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (color == null || color.length == 0) {
|
|
||||||
color = "#FF0000"; // red
|
|
||||||
}
|
|
||||||
|
|
||||||
model.color = color;
|
|
@@ -1,8 +0,0 @@
|
|||||||
<webscript>
|
|
||||||
<shortname>Calendar Subscriptions</shortname>
|
|
||||||
<description>Calendar Subscriptions</description>
|
|
||||||
<url>/calendar/setColor</url>
|
|
||||||
<authentication>user</authentication>
|
|
||||||
<transaction>required</transaction>
|
|
||||||
<lifecycle>internal</lifecycle>
|
|
||||||
</webscript>
|
|
@@ -1,2 +0,0 @@
|
|||||||
Done.
|
|
||||||
|
|
@@ -1,27 +0,0 @@
|
|||||||
function getGUIDFromNodeRef(nodeRef) {
|
|
||||||
var str = "" + nodeRef;
|
|
||||||
if (str.length > 24) {
|
|
||||||
return str.substring(24);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findNodeByNodeRef(nodeRef) {
|
|
||||||
var resultsArray = search.luceneSearch("ID:workspace\\://SpacesStore/" + getGUIDFromNodeRef(nodeRef));
|
|
||||||
if (resultsArray != null && resultsArray.length > 0) {
|
|
||||||
return resultsArray[0];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.log("COLOR: " + args.color + " REF: " + args.ref);
|
|
||||||
var spaceRef = args.ref;
|
|
||||||
var calendar = findNodeByNodeRef(spaceRef);
|
|
||||||
|
|
||||||
if (calendar != null) {
|
|
||||||
calendar.properties["ia:colorEventDefault"] = args.color;
|
|
||||||
calendar.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@@ -0,0 +1,10 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>Get filtered forum posts</shortname>
|
||||||
|
<description>Get the discussion topics that match the filters.</description>
|
||||||
|
<url>/api/forum/site/{site}/discussions/posts/filtered</url>
|
||||||
|
<url>/api/forum/discussions/posts/filtered</url>
|
||||||
|
<format default="json">argument</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction allow="readonly">required</transaction>
|
||||||
|
<lifecycle>limited_support</lifecycle>
|
||||||
|
</webscript>
|
@@ -0,0 +1,19 @@
|
|||||||
|
<#import "../post.lib.ftl" as postLib/>
|
||||||
|
<#import "../../generic-paged-results.lib.ftl" as gen/>
|
||||||
|
{
|
||||||
|
"forumPermissions":
|
||||||
|
{
|
||||||
|
<#if forum??>
|
||||||
|
"create": ${forum.hasPermission("CreateChildren")?string},
|
||||||
|
"edit": ${forum.hasPermission("Write")?string},
|
||||||
|
"delete": ${forum.hasPermission("Delete")?string}
|
||||||
|
<#else>
|
||||||
|
"create": false,
|
||||||
|
"edit": false,
|
||||||
|
"delete": false
|
||||||
|
</#if>
|
||||||
|
},
|
||||||
|
<@gen.pagedResults data=data ; item>
|
||||||
|
<@postLib.postJSON postData=item />
|
||||||
|
</@gen.pagedResults>
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>Get hot forum posts</shortname>
|
||||||
|
<description>Get the hot topics in the forum.</description>
|
||||||
|
<url>/api/forum/site/{site}/{container}/{path}/posts/hot</url>
|
||||||
|
<url>/api/forum/site/{site}/{container}/posts/hot</url>
|
||||||
|
<url>/api/forum/node/{store_type}/{store_id}/{id}/posts/hot</url>
|
||||||
|
<format default="json">argument</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction allow="readonly">required</transaction>
|
||||||
|
<lifecycle>limited_support</lifecycle>
|
||||||
|
</webscript>
|
@@ -0,0 +1,13 @@
|
|||||||
|
<#import "../post.lib.ftl" as postLib/>
|
||||||
|
<#import "../../generic-paged-results.lib.ftl" as gen/>
|
||||||
|
{
|
||||||
|
"forumPermissions":
|
||||||
|
{
|
||||||
|
"create": ${forum.hasPermission("CreateChildren")?string},
|
||||||
|
"edit": ${forum.hasPermission("Write")?string},
|
||||||
|
"delete": ${forum.hasPermission("Delete")?string}
|
||||||
|
},
|
||||||
|
<@gen.pagedResults data=data ; item>
|
||||||
|
<@postLib.postJSON postData=item />
|
||||||
|
</@gen.pagedResults>
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>Get my forum posts</shortname>
|
||||||
|
<description>Gets the forum posts created by the current user.</description>
|
||||||
|
<url>/api/forum/site/{site}/{container}/{path}/posts/myposts</url>
|
||||||
|
<url>/api/forum/site/{site}/{container}/posts/myposts</url>
|
||||||
|
<url>/api/forum/node/{store_type}/{store_id}/{id}/posts/myposts</url>
|
||||||
|
<format default="json">argument</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction allow="readonly">required</transaction>
|
||||||
|
<lifecycle>limited_support</lifecycle>
|
||||||
|
</webscript>
|
@@ -0,0 +1,13 @@
|
|||||||
|
<#import "../post.lib.ftl" as postLib/>
|
||||||
|
<#import "../../generic-paged-results.lib.ftl" as gen/>
|
||||||
|
{
|
||||||
|
"forumPermissions":
|
||||||
|
{
|
||||||
|
"create": ${forum.hasPermission("CreateChildren")?string},
|
||||||
|
"edit": ${forum.hasPermission("Write")?string},
|
||||||
|
"delete": ${forum.hasPermission("Delete")?string}
|
||||||
|
},
|
||||||
|
<@gen.pagedResults data=data ; item>
|
||||||
|
<@postLib.postJSON postData=item />
|
||||||
|
</@gen.pagedResults>
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>Get new forum posts</shortname>
|
||||||
|
<description>Gets the forum posts for the last specified number of days.</description>
|
||||||
|
<url>/api/forum/site/{site}/{container}/{path}/posts/new?numdays={numdays}</url>
|
||||||
|
<url>/api/forum/site/{site}/{container}/posts/new?numdays={numdays}</url>
|
||||||
|
<url>/api/forum/node/{store_type}/{store_id}/{id}/posts/new?numdays={numdays}</url>
|
||||||
|
<format default="json">argument</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction allow="readonly">required</transaction>
|
||||||
|
<lifecycle>limited_support</lifecycle>
|
||||||
|
</webscript>
|
@@ -0,0 +1,13 @@
|
|||||||
|
<#import "../post.lib.ftl" as postLib/>
|
||||||
|
<#import "../../generic-paged-results.lib.ftl" as gen/>
|
||||||
|
{
|
||||||
|
"forumPermissions":
|
||||||
|
{
|
||||||
|
"create": ${forum.hasPermission("CreateChildren")?string},
|
||||||
|
"edit": ${forum.hasPermission("Write")?string},
|
||||||
|
"delete": ${forum.hasPermission("Delete")?string}
|
||||||
|
},
|
||||||
|
<@gen.pagedResults data=data ; item>
|
||||||
|
<@postLib.postJSON postData=item />
|
||||||
|
</@gen.pagedResults>
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>Get forum posts</shortname>
|
||||||
|
<description>Gets the forum posts.</description>
|
||||||
|
<url>/api/forum/site/{site}/{container}/{path}/posts</url>
|
||||||
|
<url>/api/forum/site/{site}/{container}/posts</url>
|
||||||
|
<url>/api/forum/node/{store_type}/{store_id}/{id}/posts</url>
|
||||||
|
<format default="json">argument</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction allow="readonly">required</transaction>
|
||||||
|
<lifecycle>limited_support</lifecycle>
|
||||||
|
</webscript>
|
@@ -0,0 +1,19 @@
|
|||||||
|
<#import "../post.lib.ftl" as postLib/>
|
||||||
|
<#import "../../generic-paged-results.lib.ftl" as gen/>
|
||||||
|
{
|
||||||
|
"forumPermissions":
|
||||||
|
{
|
||||||
|
<#if forum.getParent()?? && forum.getTypeShort() != "st:site" >
|
||||||
|
"create": ${(forum.getParent()).hasPermission("CreateChildren")?string},
|
||||||
|
"edit": ${(forum.getParent()).hasPermission("Write")?string},
|
||||||
|
"delete": ${(forum.getParent()).hasPermission("Delete")?string}
|
||||||
|
<#else>
|
||||||
|
"create": ${forum.hasPermission("CreateChildren")?string},
|
||||||
|
"edit": ${forum.hasPermission("Write")?string},
|
||||||
|
"delete": ${forum.hasPermission("Delete")?string}
|
||||||
|
</#if>
|
||||||
|
},
|
||||||
|
<@gen.pagedResults data=data ; item>
|
||||||
|
<@postLib.postJSON postData=item />
|
||||||
|
</@gen.pagedResults>
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>Add forum post</shortname>
|
||||||
|
<description>Adds a post to a forum.</description>
|
||||||
|
<url>/api/forum/site/{site}/{container}/{path}/posts</url>
|
||||||
|
<url>/api/forum/site/{site}/{container}/posts</url>
|
||||||
|
<url>/api/forum/node/{store_type}/{store_id}/{id}/posts</url>
|
||||||
|
<format default="json">argument</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction>required</transaction>
|
||||||
|
<lifecycle>limited_support</lifecycle>
|
||||||
|
</webscript>
|
@@ -0,0 +1,4 @@
|
|||||||
|
<#import "../post.lib.ftl" as postLib />
|
||||||
|
{
|
||||||
|
"item": <@postLib.postJSON postData=postData />
|
||||||
|
}
|
@@ -0,0 +1,124 @@
|
|||||||
|
<#-- Renders a person object. -->
|
||||||
|
<#macro renderPerson person fieldName>
|
||||||
|
<#escape x as jsonUtils.encodeJSONString(x)>
|
||||||
|
"${fieldName}":
|
||||||
|
{
|
||||||
|
<#if person?has_content>
|
||||||
|
<#if person.assocs["cm:avatar"]??>
|
||||||
|
"avatarRef": "${person.assocs["cm:avatar"][0].nodeRef?string}",
|
||||||
|
</#if>
|
||||||
|
"username": "${person.properties["cm:userName"]}",
|
||||||
|
"firstName": "${person.properties["cm:firstName"]!""}",
|
||||||
|
"lastName": "${person.properties["cm:lastName"]!""}"
|
||||||
|
</#if>
|
||||||
|
},
|
||||||
|
</#escape>
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
|
||||||
|
<#macro addContent post>
|
||||||
|
<#escape x as jsonUtils.encodeJSONString(x)>
|
||||||
|
<#assign safecontent=stringUtils.stripUnsafeHTML(post.content)>
|
||||||
|
<#if (contentLength?? && contentLength > -1 && (safecontent?length > contentLength))>
|
||||||
|
"content": "${safecontent?substring(0, contentLength)}",
|
||||||
|
<#else>
|
||||||
|
"content": "${safecontent}",
|
||||||
|
</#if>
|
||||||
|
</#escape>
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
|
||||||
|
<#macro postJSON postData>
|
||||||
|
{
|
||||||
|
<@postDataJSON postData=postData />
|
||||||
|
}
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
<#macro postDataJSON postData>
|
||||||
|
<#escape x as jsonUtils.encodeJSONString(x)>
|
||||||
|
<#-- which node should be used for urls? which for the post data? -->
|
||||||
|
<#if postData.isTopicPost>
|
||||||
|
<#assign refNode=postData.topic />
|
||||||
|
<#else>
|
||||||
|
<#assign refNode=postData.post />
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#assign post=postData.post />
|
||||||
|
|
||||||
|
<#-- render topic post only data first -->
|
||||||
|
<#if postData.isTopicPost>
|
||||||
|
"name": "${postData.topic.name}",
|
||||||
|
"totalReplyCount": ${postData.totalReplyCount?c},
|
||||||
|
<#if postData.lastReply??>
|
||||||
|
"lastReplyOn": "${xmldate(postData.lastReply.properties.created)}",
|
||||||
|
<#if postData.lastReplyBy??>
|
||||||
|
<@renderPerson person=postData.lastReplyBy fieldName="lastReplyBy" />
|
||||||
|
<#else>
|
||||||
|
"lastReplyBy":
|
||||||
|
{
|
||||||
|
"username": ""
|
||||||
|
},
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
"tags": [<#list postData.tags as x>"${x}"<#if x_has_next>, </#if></#list>],
|
||||||
|
"site": "${postData.site!""}",
|
||||||
|
<#else>
|
||||||
|
"name": "${post.name}",
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#-- data using refNode which might be the topic or the post node -->
|
||||||
|
"url": "/forum/post/node/${refNode.nodeRef.storeRef.protocol}/${refNode.nodeRef.storeRef.identifier}/${refNode.nodeRef.id}",
|
||||||
|
"repliesUrl": "/forum/post/node/${refNode.nodeRef.storeRef.protocol}/${refNode.nodeRef.storeRef.identifier}/${refNode.nodeRef.id}/replies",
|
||||||
|
"nodeRef": "${refNode.nodeRef}",
|
||||||
|
|
||||||
|
<#-- data coming from the post node -->
|
||||||
|
"title": "${(post.properties.title!"")}",
|
||||||
|
"createdOn": "${xmldate(post.properties.created)}",
|
||||||
|
"modifiedOn": "${xmldate(post.properties.modified)}",
|
||||||
|
<#if (post.properties["cm:updated"]??)>
|
||||||
|
"isUpdated": true,
|
||||||
|
"updatedOn": "${xmldate(post.properties["cm:updated"])}",
|
||||||
|
<#else>
|
||||||
|
"isUpdated": false,
|
||||||
|
</#if>
|
||||||
|
<#if postData.author?? && postData.author?has_content>
|
||||||
|
<@renderPerson person=postData.author fieldName="author" />
|
||||||
|
<#else>
|
||||||
|
"author":
|
||||||
|
{
|
||||||
|
"username": "${post.properties["cm:creator"]}"
|
||||||
|
},
|
||||||
|
</#if>
|
||||||
|
<@addContent post=post />
|
||||||
|
"replyCount": <#if post.sourceAssocs["cm:references"]??>${post.sourceAssocs["cm:references"]?size?c}<#else>0</#if>,
|
||||||
|
"permissions":
|
||||||
|
{
|
||||||
|
"edit": ${postData.canEdit?string},
|
||||||
|
"reply": ${post.parent.hasPermission("CreateChildren")?string},
|
||||||
|
"delete": ${post.hasPermission("Delete")?string}
|
||||||
|
}
|
||||||
|
</#escape>
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
|
||||||
|
<#-- Renders replies.
|
||||||
|
The difference is to a normal post is that the children might be
|
||||||
|
added inline in the returned JSON.
|
||||||
|
-->
|
||||||
|
<#macro repliesJSON data>
|
||||||
|
{
|
||||||
|
<@postDataJSON postData=data />
|
||||||
|
<#if data.children?exists>
|
||||||
|
, "children": <@repliesRootJSON children=data.children />
|
||||||
|
</#if>
|
||||||
|
}
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
<#macro repliesRootJSON children>
|
||||||
|
[
|
||||||
|
<#list children as child>
|
||||||
|
<@repliesJSON data=child/>
|
||||||
|
<#if child_has_next>,</#if>
|
||||||
|
</#list>
|
||||||
|
]
|
||||||
|
</#macro>
|
@@ -0,0 +1,10 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>Get forum post replies</shortname>
|
||||||
|
<description>Get the forum post replies.</description>
|
||||||
|
<url>/api/forum/post/site/{site}/{container}/{path}/replies</url>
|
||||||
|
<url>/api/forum/post/node/{store_type}/{store_id}/{id}/replies</url>
|
||||||
|
<format default="json">argument</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction allow="readonly">required</transaction>
|
||||||
|
<lifecycle>limited_support</lifecycle>
|
||||||
|
</webscript>
|
@@ -0,0 +1,4 @@
|
|||||||
|
<#import "../post.lib.ftl" as postLib />
|
||||||
|
{
|
||||||
|
"items": <@postLib.repliesRootJSON children=data />
|
||||||
|
}
|
@@ -0,0 +1,9 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>Add forum post reply</shortname>
|
||||||
|
<description>Adds a reply to a post.</description>
|
||||||
|
<url>/api/forum/post/node/{store_type}/{store_id}/{id}/replies</url>
|
||||||
|
<format default="json">argument</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction>required</transaction>
|
||||||
|
<lifecycle>limited_support</lifecycle>
|
||||||
|
</webscript>
|
@@ -0,0 +1,4 @@
|
|||||||
|
<#import "../post.lib.ftl" as postLib />
|
||||||
|
{
|
||||||
|
"item": <@postLib.postJSON postData=postData />
|
||||||
|
}
|
@@ -0,0 +1,10 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>Delete topic</shortname>
|
||||||
|
<description>Deletes a topic.</description>
|
||||||
|
<url>/api/forum/post/site/{site}/{container}/{path}</url>
|
||||||
|
<url>/api/forum/post/node/{store_type}/{store_id}/{id}</url>
|
||||||
|
<format default="json">argument</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction>required</transaction>
|
||||||
|
<lifecycle>limited_support</lifecycle>
|
||||||
|
</webscript>
|
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"message" : "${message}"
|
||||||
|
}
|
@@ -0,0 +1,2 @@
|
|||||||
|
forum-post.msg.deleted=Node {0} deleted
|
||||||
|
forum-post.msg.marked.removed=Node {0} marked as removed
|
@@ -0,0 +1,2 @@
|
|||||||
|
forum-post.msg.deleted=Node {0} gel\u00f6scht
|
||||||
|
forum-post.msg.marked.removed=Node {0} als entfernt gekennzeichnet
|
@@ -0,0 +1,2 @@
|
|||||||
|
forum-post.msg.deleted=Nodo {0} eliminado
|
||||||
|
forum-post.msg.marked.removed=Nodo {0} marcado como eliminado
|
@@ -0,0 +1,2 @@
|
|||||||
|
forum-post.msg.deleted=N\u0153ud {0} supprim\u00e9
|
||||||
|
forum-post.msg.marked.removed=N\u0153ud {0} marqu\u00e9 comme supprim\u00e9
|
@@ -0,0 +1,2 @@
|
|||||||
|
forum-post.msg.deleted=Nodo {0} eliminato
|
||||||
|
forum-post.msg.marked.removed=Nodo {0} contrassegnato come rimosso
|
@@ -0,0 +1,2 @@
|
|||||||
|
forum-post.msg.deleted=\u30ce\u30fc\u30c9 ''{0}'' \u304c\u524a\u9664\u3055\u308c\u307e\u3057\u305f
|
||||||
|
forum-post.msg.marked.removed=\u30ce\u30fc\u30c9 "{0}" \u304c\u524a\u9664\u6e08\u307f\u3068\u3057\u3066\u30de\u30fc\u30af\u3055\u308c\u307e\u3057\u305f
|
@@ -0,0 +1,2 @@
|
|||||||
|
forum-post.msg.deleted=Slettet node {0}
|
||||||
|
forum-post.msg.marked.removed=Node {0} er merket som slettet
|
@@ -0,0 +1,2 @@
|
|||||||
|
forum-post.msg.deleted=Node {0} verwijderd
|
||||||
|
forum-post.msg.marked.removed=Node {0} gemarkeerd als verwijderd
|
@@ -0,0 +1,2 @@
|
|||||||
|
forum-post.msg.deleted=N\u00f3 {0} exclu\u00eddo
|
||||||
|
forum-post.msg.marked.removed=N\u00f3 {0} marcado como removido
|
@@ -0,0 +1,2 @@
|
|||||||
|
forum-post.msg.deleted=\u0423\u0437\u0435\u043b {0} \u0443\u0434\u0430\u043b\u0435\u043d
|
||||||
|
forum-post.msg.marked.removed=\u0423\u0437\u0435\u043b {0} \u043e\u0442\u043c\u0435\u0447\u0435\u043d \u043a\u0430\u043a \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0439
|
@@ -0,0 +1,2 @@
|
|||||||
|
forum-post.msg.deleted=\u5df2\u5220\u9664\u8282\u70b9 {0}
|
||||||
|
forum-post.msg.marked.removed=\u8282\u70b9 {0} \u6807\u8bb0\u4e3a\u5df2\u79fb\u9664
|
@@ -0,0 +1,10 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>Get topic details</shortname>
|
||||||
|
<description>Gets the details for a topic.</description>
|
||||||
|
<url>/api/forum/post/site/{site}/{container}/{path}</url>
|
||||||
|
<url>/api/forum/post/node/{store_type}/{store_id}/{id}</url>
|
||||||
|
<format default="json">argument</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction allow="readonly">required</transaction>
|
||||||
|
<lifecycle>limited_support</lifecycle>
|
||||||
|
</webscript>
|
@@ -0,0 +1,4 @@
|
|||||||
|
<#import "../post.lib.ftl" as postLib />
|
||||||
|
{
|
||||||
|
"item": <@postLib.postJSON postData=postData />
|
||||||
|
}
|
@@ -0,0 +1,10 @@
|
|||||||
|
<webscript>
|
||||||
|
<shortname>Update topic</shortname>
|
||||||
|
<description>Updates a topic.</description>
|
||||||
|
<url>/api/forum/post/site/{site}/{container}/{path}</url>
|
||||||
|
<url>/api/forum/post/node/{store_type}/{store_id}/{id}</url>
|
||||||
|
<format default="json">argument</format>
|
||||||
|
<authentication>user</authentication>
|
||||||
|
<transaction>required</transaction>
|
||||||
|
<lifecycle>limited_support</lifecycle>
|
||||||
|
</webscript>
|
@@ -0,0 +1,4 @@
|
|||||||
|
<#import "../post.lib.ftl" as postLib />
|
||||||
|
{
|
||||||
|
"item": <@postLib.postJSON postData=postData />
|
||||||
|
}
|
@@ -1329,6 +1329,89 @@
|
|||||||
parent="abstractLinksWebScript">
|
parent="abstractLinksWebScript">
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
<!-- Discussions Pages REST API -->
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
|
<!-- abstract discussions web script -->
|
||||||
|
<bean id="abstractDiscussionWebScript" parent="webscript" abstract="true">
|
||||||
|
<property name="nodeService" ref="NodeService"/>
|
||||||
|
<property name="siteService" ref="SiteService"/>
|
||||||
|
<property name="personService" ref="PersonService"/>
|
||||||
|
<property name="activityService" ref="activityService"/>
|
||||||
|
<property name="discussionService" ref="DiscussionService"/>
|
||||||
|
<property name="permissionService" ref="PermissionService" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Fetches the details of one discussions post or topic -->
|
||||||
|
<bean id="webscript.org.alfresco.repository.discussions.posts.forum-post.get"
|
||||||
|
class="org.alfresco.repo.web.scripts.discussion.ForumPostGet"
|
||||||
|
parent="abstractDiscussionWebScript">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Updates a discussions post or topic -->
|
||||||
|
<bean id="webscript.org.alfresco.repository.discussions.posts.forum-post.put"
|
||||||
|
class="org.alfresco.repo.web.scripts.discussion.ForumPostPut"
|
||||||
|
parent="abstractDiscussionWebScript">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Deletes a discussion post or topic -->
|
||||||
|
<bean id="webscript.org.alfresco.repository.discussions.posts.forum-post.delete"
|
||||||
|
class="org.alfresco.repo.web.scripts.discussion.ForumPostDelete"
|
||||||
|
parent="abstractDiscussionWebScript">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Creates a new discussions reply post for a topic -->
|
||||||
|
<bean id="webscript.org.alfresco.repository.discussions.posts.forum-post-replies.post"
|
||||||
|
class="org.alfresco.repo.web.scripts.discussion.ForumPostRepliesPost"
|
||||||
|
parent="abstractDiscussionWebScript">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Lists the discussions replies for a topic or post -->
|
||||||
|
<bean id="webscript.org.alfresco.repository.discussions.posts.forum-post-replies.get"
|
||||||
|
class="org.alfresco.repo.web.scripts.discussion.ForumPostRepliesGet"
|
||||||
|
parent="abstractDiscussionWebScript">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Creates a new discussions topic and primary post -->
|
||||||
|
<bean id="webscript.org.alfresco.repository.discussions.forum.forum-posts.post"
|
||||||
|
class="org.alfresco.repo.web.scripts.discussion.ForumTopicPost"
|
||||||
|
parent="abstractDiscussionWebScript">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Lists the discussion topics for a site -->
|
||||||
|
<bean id="webscript.org.alfresco.repository.discussions.forum.forum-posts.get"
|
||||||
|
class="org.alfresco.repo.web.scripts.discussion.ForumTopicsGet"
|
||||||
|
parent="abstractDiscussionWebScript">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Lists the discussion topics for the user of a site -->
|
||||||
|
<bean id="webscript.org.alfresco.repository.discussions.forum.forum-posts-mine.get"
|
||||||
|
class="org.alfresco.repo.web.scripts.discussion.ForumTopicsMineGet"
|
||||||
|
parent="abstractDiscussionWebScript">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Lists the recent discussion topics for a site -->
|
||||||
|
<bean id="webscript.org.alfresco.repository.discussions.forum.forum-posts-new.get"
|
||||||
|
class="org.alfresco.repo.web.scripts.discussion.ForumTopicsRecentGet"
|
||||||
|
parent="abstractDiscussionWebScript">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Lists the discussion topics with recent replies for a site -->
|
||||||
|
<bean id="webscript.org.alfresco.repository.discussions.forum.forum-posts-hot.get"
|
||||||
|
class="org.alfresco.repo.web.scripts.discussion.ForumTopicsHotGet"
|
||||||
|
parent="abstractDiscussionWebScript">
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- Lists the discussion topics matching filters -->
|
||||||
|
<bean id="webscript.org.alfresco.repository.discussions.forum.forum-posts-filtered.get"
|
||||||
|
class="org.alfresco.repo.web.scripts.discussion.ForumTopicsFilteredGet"
|
||||||
|
parent="abstractDiscussionWebScript">
|
||||||
|
<property name="nodeService" ref="NodeService" />
|
||||||
|
<property name="searchService" ref="SearchService" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
<!-- Slingshot Calendar REST API -->
|
<!-- Slingshot Calendar REST API -->
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
@@ -42,6 +42,7 @@ import org.junit.runners.Suite;
|
|||||||
org.alfresco.repo.web.scripts.audit.AuditWebScriptTest.class,
|
org.alfresco.repo.web.scripts.audit.AuditWebScriptTest.class,
|
||||||
org.alfresco.repo.web.scripts.blogs.BlogServiceTest.class,
|
org.alfresco.repo.web.scripts.blogs.BlogServiceTest.class,
|
||||||
org.alfresco.repo.web.scripts.dictionary.DictionaryRestApiTest.class,
|
org.alfresco.repo.web.scripts.dictionary.DictionaryRestApiTest.class,
|
||||||
|
org.alfresco.repo.web.scripts.discussion.DiscussionRestApiTest.class,
|
||||||
org.alfresco.repo.web.scripts.activities.feed.control.FeedControlTest.class,
|
org.alfresco.repo.web.scripts.activities.feed.control.FeedControlTest.class,
|
||||||
org.alfresco.repo.web.scripts.forms.FormRestApiGet_Test.class,
|
org.alfresco.repo.web.scripts.forms.FormRestApiGet_Test.class,
|
||||||
org.alfresco.repo.web.scripts.forms.FormRestApiJsonPost_Test.class,
|
org.alfresco.repo.web.scripts.forms.FormRestApiJsonPost_Test.class,
|
||||||
|
@@ -58,6 +58,7 @@ public class ReadOnlyTransactionInGetRestApiTest extends BaseWebScriptTest
|
|||||||
private static final String TEST_SITE_NAME = "readOnlyTestSite";
|
private static final String TEST_SITE_NAME = "readOnlyTestSite";
|
||||||
|
|
||||||
private static final String URL_GET_SITE_BLOG = "/api/blog/site/" + TEST_SITE_NAME + "/blog";
|
private static final String URL_GET_SITE_BLOG = "/api/blog/site/" + TEST_SITE_NAME + "/blog";
|
||||||
|
private static final String URL_GET_SITE_FORUM_POSTS = "/api/forum/site/" + TEST_SITE_NAME + "/discussions/posts";
|
||||||
private static final String URL_GET_SITE_LINKS = "/api/links/site/" + TEST_SITE_NAME + "/links?page=1&pageSize=10";
|
private static final String URL_GET_SITE_LINKS = "/api/links/site/" + TEST_SITE_NAME + "/links?page=1&pageSize=10";
|
||||||
private static final String URL_GET_SITE_LINK = "/api/links/link/site/" + TEST_SITE_NAME + "/links/123456789";
|
private static final String URL_GET_SITE_LINK = "/api/links/link/site/" + TEST_SITE_NAME + "/links/123456789";
|
||||||
private static final String URL_GET_SITE_TAGS = "/api/tagscopes/site/" + TEST_SITE_NAME + "/tags";
|
private static final String URL_GET_SITE_TAGS = "/api/tagscopes/site/" + TEST_SITE_NAME + "/tags";
|
||||||
@@ -141,6 +142,13 @@ public class ReadOnlyTransactionInGetRestApiTest extends BaseWebScriptTest
|
|||||||
assertEquals(Status.STATUS_OK, response.getStatus());
|
assertEquals(Status.STATUS_OK, response.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testGetSiteForumPosts() throws Exception
|
||||||
|
{
|
||||||
|
Response response = sendRequest(new GetRequest(URL_GET_SITE_FORUM_POSTS), 200);
|
||||||
|
logResponse(response);
|
||||||
|
assertEquals(Status.STATUS_OK, response.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
public void testGetSiteLinks() throws Exception
|
public void testGetSiteLinks() throws Exception
|
||||||
{
|
{
|
||||||
Response response = sendRequest(new GetRequest(URL_GET_SITE_LINKS), 200);
|
Response response = sendRequest(new GetRequest(URL_GET_SITE_LINKS), 200);
|
||||||
|
@@ -37,6 +37,7 @@ import org.alfresco.repo.web.scripts.blogs.BlogServiceTest;
|
|||||||
import org.alfresco.repo.web.scripts.comment.CommentsApiTest;
|
import org.alfresco.repo.web.scripts.comment.CommentsApiTest;
|
||||||
import org.alfresco.repo.web.scripts.custommodel.CustomModelImportTest;
|
import org.alfresco.repo.web.scripts.custommodel.CustomModelImportTest;
|
||||||
import org.alfresco.repo.web.scripts.dictionary.DictionaryRestApiTest;
|
import org.alfresco.repo.web.scripts.dictionary.DictionaryRestApiTest;
|
||||||
|
import org.alfresco.repo.web.scripts.discussion.DiscussionRestApiTest;
|
||||||
import org.alfresco.repo.web.scripts.facet.FacetRestApiTest;
|
import org.alfresco.repo.web.scripts.facet.FacetRestApiTest;
|
||||||
import org.alfresco.repo.web.scripts.forms.FormRestApiGet_Test;
|
import org.alfresco.repo.web.scripts.forms.FormRestApiGet_Test;
|
||||||
import org.alfresco.repo.web.scripts.forms.FormRestApiJsonPost_Test;
|
import org.alfresco.repo.web.scripts.forms.FormRestApiJsonPost_Test;
|
||||||
@@ -81,6 +82,7 @@ public class WebScriptTestSuite extends TestSuite
|
|||||||
suite.addTestSuite( AuditWebScriptTest.class );
|
suite.addTestSuite( AuditWebScriptTest.class );
|
||||||
suite.addTestSuite( BlogServiceTest.class );
|
suite.addTestSuite( BlogServiceTest.class );
|
||||||
suite.addTestSuite( DictionaryRestApiTest.class );
|
suite.addTestSuite( DictionaryRestApiTest.class );
|
||||||
|
suite.addTestSuite( DiscussionRestApiTest.class );
|
||||||
suite.addTestSuite( FeedControlTest.class );
|
suite.addTestSuite( FeedControlTest.class );
|
||||||
suite.addTestSuite( FormRestApiGet_Test.class );
|
suite.addTestSuite( FormRestApiGet_Test.class );
|
||||||
suite.addTestSuite( FormRestApiJsonPost_Test.class );
|
suite.addTestSuite( FormRestApiJsonPost_Test.class );
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -115,6 +115,8 @@ public class TestFavourites extends AbstractBaseApiTest
|
|||||||
private String person12Id;
|
private String person12Id;
|
||||||
private TestPerson person14;
|
private TestPerson person14;
|
||||||
private String person14Id;
|
private String person14Id;
|
||||||
|
private TestPerson person15;
|
||||||
|
private String person15Id;
|
||||||
|
|
||||||
private TestNetwork network2;
|
private TestNetwork network2;
|
||||||
private TestPerson person21;
|
private TestPerson person21;
|
||||||
@@ -176,6 +178,11 @@ public class TestFavourites extends AbstractBaseApiTest
|
|||||||
TestFavourites.this.person14 = network1.createUser(personInfo);
|
TestFavourites.this.person14 = network1.createUser(personInfo);
|
||||||
assertNotNull(TestFavourites.this.person14);
|
assertNotNull(TestFavourites.this.person14);
|
||||||
TestFavourites.this.person14Id = TestFavourites.this.person14.getId();
|
TestFavourites.this.person14Id = TestFavourites.this.person14.getId();
|
||||||
|
name = GUID.generate();
|
||||||
|
personInfo = new PersonInfo(name, name, name, "password", null, null, null, null, null, null, null);
|
||||||
|
TestFavourites.this.person15 = network1.createUser(personInfo);
|
||||||
|
assertNotNull(TestFavourites.this.person15);
|
||||||
|
TestFavourites.this.person15Id = TestFavourites.this.person15.getId();
|
||||||
|
|
||||||
TestFavourites.this.network2 = networksIt.next();
|
TestFavourites.this.network2 = networksIt.next();
|
||||||
name = GUID.generate();
|
name = GUID.generate();
|
||||||
@@ -949,6 +956,22 @@ public class TestFavourites extends AbstractBaseApiTest
|
|||||||
assertEquals(HttpStatus.SC_METHOD_NOT_ALLOWED, e.getHttpResponse().getStatusCode());
|
assertEquals(HttpStatus.SC_METHOD_NOT_ALLOWED, e.getHttpResponse().getStatusCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// invalid orderBy param
|
||||||
|
{
|
||||||
|
publicApiClient.setRequestContext(new RequestContext(network1.getId(), person10Id));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put("orderBy", "invalid ASC");
|
||||||
|
favouritesProxy.getFavourites(person10Id, createParams(null, params));
|
||||||
|
}
|
||||||
|
catch(PublicApiException e)
|
||||||
|
{
|
||||||
|
assertEquals(HttpStatus.SC_BAD_REQUEST, e.getHttpResponse().getStatusCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1912,6 +1935,60 @@ public class TestFavourites extends AbstractBaseApiTest
|
|||||||
assertTrue(node1.getIsFavorite());
|
assertTrue(node1.getIsFavorite());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test sort favourites using 'orderBy' parameter.
|
||||||
|
*
|
||||||
|
* <p>GET:</p>
|
||||||
|
* {@literal <host>:<port>/alfresco/api/<networkId>/public/alfresco/versions/1/people/<userName>/favorites?orderBy}
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSortFavourites() throws Exception
|
||||||
|
{
|
||||||
|
setRequestContext(network1.getId(), person15Id, "password");
|
||||||
|
|
||||||
|
final NodeRef folderNodeRef1 = person1PublicFolders.get(0); // person1's folder (Test Folder1)
|
||||||
|
final NodeRef folderNodeRef2 = person1PublicFolders.get(1); // person1's folder (Test Folder2)
|
||||||
|
final NodeRef folderNodeRef3 = person1PublicFolders.get(2); // person1's folder (Test Folder3)
|
||||||
|
final NodeRef nodeRef1= person1PublicDocs.get(0); // a file (Test Doc1)
|
||||||
|
final NodeRef nodeRef2 = person1PublicDocs.get(1); // a file (Test Doc2)
|
||||||
|
|
||||||
|
// Favourite the docs and folders
|
||||||
|
Favourite folder1Favourite = makeFolderFavourite(folderNodeRef1.getId());
|
||||||
|
favouritesProxy.createFavourite(person15Id, folder1Favourite);
|
||||||
|
Favourite folder2Favourite = makeFolderFavourite(folderNodeRef2.getId());
|
||||||
|
favouritesProxy.createFavourite(person15Id, folder2Favourite);
|
||||||
|
Favourite folder3Favourite = makeFolderFavourite(folderNodeRef3.getId());
|
||||||
|
favouritesProxy.createFavourite(person15Id, folder3Favourite);
|
||||||
|
Favourite file1Favourite = makeFileFavourite(nodeRef1.getId());
|
||||||
|
favouritesProxy.createFavourite(person15Id, file1Favourite);
|
||||||
|
Favourite file2Favourite = makeFileFavourite(nodeRef2.getId());
|
||||||
|
favouritesProxy.createFavourite(person15Id, file2Favourite);
|
||||||
|
|
||||||
|
// Order by title ASC
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put("orderBy", "title ASC");
|
||||||
|
|
||||||
|
List<Favourite> favourites = favouritesProxy.getFavourites(person15Id, createParams(null,params)).getList();
|
||||||
|
assertTrue(favourites.size() == 5);
|
||||||
|
assertTrue(favourites.get(0).getTargetGuid().equals(nodeRef1.getId()));
|
||||||
|
assertTrue(favourites.get(1).getTargetGuid().equals(nodeRef2.getId()));
|
||||||
|
assertTrue(favourites.get(2).getTargetGuid().equals(folderNodeRef1.getId()));
|
||||||
|
assertTrue(favourites.get(3).getTargetGuid().equals(folderNodeRef2.getId()));
|
||||||
|
assertTrue(favourites.get(4).getTargetGuid().equals(folderNodeRef3.getId()));
|
||||||
|
|
||||||
|
// Order by type ASC, title DESC
|
||||||
|
params = new HashMap<>();
|
||||||
|
params.put("orderBy", "type DESC, title DESC");
|
||||||
|
|
||||||
|
favourites = favouritesProxy.getFavourites(person15Id, createParams(null,params)).getList();
|
||||||
|
assertTrue(favourites.size() == 5);
|
||||||
|
assertTrue(favourites.get(0).getTargetGuid().equals(folderNodeRef3.getId()));
|
||||||
|
assertTrue(favourites.get(1).getTargetGuid().equals(folderNodeRef2.getId()));
|
||||||
|
assertTrue(favourites.get(2).getTargetGuid().equals(folderNodeRef1.getId()));
|
||||||
|
assertTrue(favourites.get(3).getTargetGuid().equals(nodeRef2.getId()));
|
||||||
|
assertTrue(favourites.get(4).getTargetGuid().equals(nodeRef1.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
private void assertPathInfo(PathInfo expectedPathInfo, String expectedPathName, boolean expectedIsComplete)
|
private void assertPathInfo(PathInfo expectedPathInfo, String expectedPathName, boolean expectedIsComplete)
|
||||||
{
|
{
|
||||||
assertNotNull("Path info was requested.", expectedPathInfo);
|
assertNotNull("Path info was requested.", expectedPathInfo);
|
||||||
|
Reference in New Issue
Block a user