package org.sakaiproject.component.app.messageforums.entity;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.api.app.messageforums.Area;
import org.sakaiproject.api.app.messageforums.DiscussionForum;
import org.sakaiproject.api.app.messageforums.DiscussionTopic;
import org.sakaiproject.api.app.messageforums.MessageForumsMessageManager;
import org.sakaiproject.api.app.messageforums.MessageForumsTypeManager;
import org.sakaiproject.api.app.messageforums.PrivateForum;
import org.sakaiproject.api.app.messageforums.PrivateTopic;
import org.sakaiproject.api.app.messageforums.Topic;
import org.sakaiproject.api.app.messageforums.entity.DecoratedForumInfo;
import org.sakaiproject.api.app.messageforums.entity.DecoratedTopicInfo;
import org.sakaiproject.api.app.messageforums.entity.ForumMessageEntityProvider;
import org.sakaiproject.api.app.messageforums.entity.TopicEntityProvider;
import org.sakaiproject.api.app.messageforums.ui.DiscussionForumManager;
import org.sakaiproject.api.app.messageforums.ui.PrivateMessageManager;
import org.sakaiproject.api.app.messageforums.ui.UIPermissionsManager;
import org.sakaiproject.component.app.messageforums.dao.hibernate.PrivateTopicImpl;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.entitybroker.EntityReference;
import org.sakaiproject.entitybroker.EntityView;
import org.sakaiproject.entitybroker.entityprovider.annotations.EntityCustomAction;
import org.sakaiproject.entitybroker.entityprovider.capabilities.ActionsExecutable;
import org.sakaiproject.entitybroker.entityprovider.capabilities.AutoRegisterEntityProvider;
import org.sakaiproject.entitybroker.entityprovider.capabilities.CollectionResolvable;
import org.sakaiproject.entitybroker.entityprovider.capabilities.PropertyProvideable;
import org.sakaiproject.entitybroker.entityprovider.capabilities.RESTful;
import org.sakaiproject.entitybroker.entityprovider.capabilities.RequestAware;
import org.sakaiproject.entitybroker.entityprovider.capabilities.RequestStorable;
import org.sakaiproject.entitybroker.entityprovider.extension.Formats;
import org.sakaiproject.entitybroker.entityprovider.extension.RequestGetter;
import org.sakaiproject.entitybroker.entityprovider.extension.RequestStorage;
import org.sakaiproject.entitybroker.entityprovider.search.Restriction;
import org.sakaiproject.entitybroker.entityprovider.search.Search;
import org.sakaiproject.user.cover.UserDirectoryService;
import org.sakaiproject.util.ResourceLoader;
public class TopicEntityProviderImpl implements TopicEntityProvider,
AutoRegisterEntityProvider, PropertyProvideable, RESTful, RequestStorable, RequestAware, ActionsExecutable {
private DiscussionForumManager forumManager;
private UIPermissionsManager uiPermissionsManager;
private MessageForumsMessageManager messageManager;
private MessageForumsTypeManager typeManager;
private PrivateMessageManager privateMessageManager;
private static final ResourceLoader rb = new ResourceLoader("org.sakaiproject.api.app.messagecenter.bundle.Messages");
private static final Log LOG = LogFactory.getLog(TopicEntityProviderImpl.class);
public static final String PVTMSG_MODE_DRAFT = "Drafts";
private RequestStorage requestStorage;
public void setRequestStorage(RequestStorage requestStorage) {
this.requestStorage = requestStorage;
}
private RequestGetter requestGetter;
public void setRequestGetter(RequestGetter requestGetter){
this.requestGetter = requestGetter;
}
public String getEntityPrefix() {
return ENTITY_PREFIX;
}
public boolean entityExists(String id) {
Topic topic = null;
try {
topic = forumManager.getTopicById(new Long(id));
}
catch (Exception e) {
e.printStackTrace();
}
return (topic != null);
}
public List<String> findEntityRefs(String[] prefixes, String[] name, String[] searchValue,
boolean exactMatch) {
List<String> rv = new ArrayList<String>();
String forumId = null;
String userId = null;
String siteId = null;
if (ENTITY_PREFIX.equals(prefixes[0])) {
for (int i = 0; i < name.length; i++) {
if ("context".equalsIgnoreCase(name[i]) || "site".equalsIgnoreCase(name[i]))
siteId = searchValue[i];
else if ("user".equalsIgnoreCase(name[i]) || "userId".equalsIgnoreCase(name[i]))
userId = searchValue[i];
else if ("parentReference".equalsIgnoreCase(name[i])) {
String[] parts = searchValue[i].split("/");
forumId = parts[parts.length - 1];
}
}
String siteRef = siteId;
if(siteRef != null && !siteRef.startsWith("/site/")){
siteRef = "/site/" + siteRef;
}
// TODO: need a way to generate the url with out having siteId in search
if (forumId != null && userId != null) {
DiscussionForum forum = forumManager.getForumByIdWithTopics(new Long(forumId));
List<Topic> topics = forum.getTopics();
for (int i = 0; i < topics.size(); i++) {
// TODO: authz is way too basic, someone more hip to message center please improve...
//This should also allow people with read access to an item to link to it
if (forumManager.isInstructor(userId, siteRef)
|| userId.equals(topics.get(i).getCreatedBy()))
rv.add("/" + ENTITY_PREFIX + "/" + topics.get(i).getId().toString());
}
}
else if (siteId != null && userId != null) {
List<DiscussionForum> forums = forumManager.getDiscussionForumsByContextId(siteId);
for (int i = 0; i < forums.size(); i++) {
List<Topic> topics = forums.get(i).getTopics();
for (int j = 0; j < topics.size(); j++) {
// TODO: authz is way too basic, someone more hip to message center please improve...
//This should also allow people with read access to an item to link to it
if (forumManager.isInstructor(userId, siteRef)
|| userId.equals(topics.get(j).getCreatedBy()))
rv.add("/" + ENTITY_PREFIX + "/" + topics.get(j).getId().toString());
}
}
}
}
return rv;
}
public Map<String, String> getProperties(String reference) {
Map<String, String> props = new HashMap<String, String>();
Topic topic =
forumManager.getTopicById(new Long(reference.substring(reference.lastIndexOf("/") + 1)));
props.put("title", topic.getTitle());
props.put("author", topic.getCreatedBy());
if (topic.getCreated() != null)
props.put("date", DateFormat.getInstance().format(topic.getCreated()));
if (topic.getModified() != null) {
props.put("modified_by", topic.getModifiedBy());
props.put("modified_date", DateFormat.getInstance().format(topic.getModified()));
}
props.put("short_description", topic.getShortDescription());
props.put("description", topic.getExtendedDescription());
if (topic.getModerated() != null)
props.put("moderated", topic.getModerated().toString());
props.put("child_provider", ForumMessageEntityProvider.ENTITY_PREFIX);
return props;
}
public String getPropertyValue(String reference, String name) {
// TODO: don't be so lazy, just get what we need...
Map<String, String> props = getProperties(reference);
return props.get(name);
}
public void setPropertyValue(String reference, String name, String value) {
// This does nothing for now... we could all the setting of many published assessment properties
// here though... if you're feeling jumpy feel free.
}
public void setForumManager(DiscussionForumManager forumManager) {
this.forumManager = forumManager;
}
public String createEntity(EntityReference ref, Object entity,
Map<String, Object> params) {
// TODO Auto-generated method stub
return null;
}
public Object getSampleEntity() {
// TODO Auto-generated method stub
return null;
}
public void updateEntity(EntityReference ref, Object entity,
Map<String, Object> params) {
// TODO Auto-generated method stub
}
public Object getEntity(EntityReference ref) {
// TODO Auto-generated method stub
return null;
}
public void deleteEntity(EntityReference ref, Map<String, Object> params) {
// TODO Auto-generated method stub
}
public List<?> getEntities(EntityReference ref, Search search) {
String siteId = null;
String forumId = null;
boolean privateMessages = false;
if (! search.isEmpty()) {
Restriction locRes = search.getRestrictionByProperty(CollectionResolvable.SEARCH_LOCATION_REFERENCE);
if (locRes != null) {
ForumSearch fs = findLocationByReference(locRes.getStringValue());
siteId = fs.siteId;
forumId = fs.forumId;
privateMessages = fs.isPrivate;
}
}
String userId = UserDirectoryService.getCurrentUser().getId();
if(userId == null || "".equals(userId)){
return null;
}
List<DecoratedForumInfo> dForums = new ArrayList<DecoratedForumInfo>();
if(privateMessages && siteId != null){
DecoratedForumInfo dForum = new DecoratedForumInfo(0L, "Messages");
Area area = getPrivateMessageManager().getPrivateMessageArea(siteId);
if (area != null){
List aggregateList = new ArrayList();
PrivateForum pf = getPrivateMessageManager().initializePrivateMessageArea(area, aggregateList, userId, siteId);
pf = getPrivateMessageManager().initializationHelper(pf, area, userId);
List pvtTopics = pf.getTopics();
Collections.sort(pvtTopics, PrivateTopicImpl.TITLE_COMPARATOR); //changed to date comparator
List topicsbyLocalization= new ArrayList();// only three folder supported, if need more, please modifify here
String local_received=rb.getString("pvt_received");
String local_sent = rb.getString("pvt_sent");
String local_deleted= rb.getString("pvt_deleted");
String current_NAV= rb.getString("pvt_message_nav");
topicsbyLocalization.add(local_received);
topicsbyLocalization.add(local_sent);
topicsbyLocalization.add(local_deleted);
int countForFolderNum = 0;// only three folder
Iterator iterator = pvtTopics.iterator();
for (int indexlittlethanTHREE=0;indexlittlethanTHREE<3;indexlittlethanTHREE++)//Iterator iterator = pvtTopics.iterator(); iterator.hasNext();)//only three times
{
PrivateTopic topic = (PrivateTopic) iterator.next();
if (topic != null)
{
String CurrentTopicTitle= topic.getTitle();//folder name
/** filter topics by context and type*/
if (topic.getTypeUuid() != null
&& topic.getTypeUuid().equals(typeManager.getUserDefinedPrivateTopicType())
&& topic.getContextId() != null && !topic.getContextId().equals(getPrivateMessageManager().getContextId())){
continue;
}
String typeUuid=""; // folder uuid
if(getLanguage(CurrentTopicTitle).toString().equals(getLanguage(current_NAV).toString()))
{
typeUuid = getPrivateMessageTypeFromContext(topicsbyLocalization.get(countForFolderNum).toString());
}
else
{
typeUuid = getPrivateMessageTypeFromContext(topic.getTitle());
}
countForFolderNum++;
int totalNoMessages = getPrivateMessageManager().findMessageCount(typeUuid, aggregateList);
int totalUnreadMessages = getPrivateMessageManager().findUnreadMessageCount(typeUuid, aggregateList);
DecoratedTopicInfo dTopicInfo = new DecoratedTopicInfo(topic.getId(), topic.getTitle(),totalUnreadMessages, totalNoMessages, typeUuid);
dForum.addTopic(dTopicInfo);
}
}
while(iterator.hasNext())//add more folder
{
PrivateTopic topic = (PrivateTopic) iterator.next();
if (topic != null)
{
/** filter topics by context and type*/
if (topic.getTypeUuid() != null
&& topic.getTypeUuid().equals(typeManager.getUserDefinedPrivateTopicType())
&& topic.getContextId() != null && !topic.getContextId().equals(siteId)){
continue;
}
String typeUuid = getPrivateMessageTypeFromContext(topic.getTitle());
int totalNoMessages = getPrivateMessageManager().findMessageCount(typeUuid, aggregateList);
int totalUnreadMessages = getPrivateMessageManager().findUnreadMessageCount(typeUuid,aggregateList);
DecoratedTopicInfo dTopicInfo = new DecoratedTopicInfo(topic.getId(), topic.getTitle(),totalUnreadMessages, totalNoMessages, typeUuid);
dForum.addTopic(dTopicInfo);
}
}
}
dForums.add(dForum);
}else if ((siteId != null && !"".equals(siteId)) || (forumId != null && !"".equals(forumId))) {
List<DiscussionForum> forums = new ArrayList<DiscussionForum>();
if(forumId != null && !"".equals(forumId)){
DiscussionForum forum = forumManager.getForumByIdWithTopics(new Long(forumId));
siteId = forumManager.getContextForForumById(forum.getId());
forums.add(forum);
}else{
forums = forumManager.getDiscussionForumsByContextId(siteId);
}
for (DiscussionForum forum : forums) {
if(forum.getDraft().equals(Boolean.FALSE)){
DecoratedForumInfo dForum = new DecoratedForumInfo(forum.getId(), forum.getTitle());
List<DiscussionTopic> topics = forum.getTopics();
int viewableTopics = 0;
for (DiscussionTopic topic : topics) {
if(topic.getDraft().equals(Boolean.FALSE)){
if (forumManager.isInstructor(userId, siteId) ||
getUiPermissionsManager().isRead(topic.getId(), topic.getDraft(), forum.getDraft(), userId, siteId))
{
int unreadMessages = 0;
int totalMessages = 0;
if (!topic.getModerated().booleanValue()
|| (topic.getModerated().booleanValue() &&
getUiPermissionsManager().isModeratePostings(topic.getId(), forum.getLocked(), forum.getDraft(), topic.getLocked(), topic.getDraft(), userId, siteId))){
unreadMessages = getMessageManager().findUnreadMessageCountByTopicIdByUserId(topic.getId(), userId);
}
else
{
// b/c topic is moderated and user does not have mod perm, user may only
// see approved msgs or pending/denied msgs authored by user
unreadMessages = getMessageManager().findUnreadViewableMessageCountByTopicIdByUserId(topic.getId(), userId);
}
totalMessages = getMessageManager().findViewableMessageCountByTopicIdByUserId(topic.getId(), userId);
dForum.addTopic(new DecoratedTopicInfo(topic.getId(), topic.getTitle(), unreadMessages, totalMessages, ""));
viewableTopics++;
}
}
}
// TODO this is a bit too simplistic but will do for now. better to be more restrictive than less at this point
// "instructor" type users can view all forums. others may view the forum if they can view at least one topic within the forum
if (forumManager.isInstructor(userId, siteId) || viewableTopics > 0) {
dForums.add(dForum);
}
}
}
}
return dForums;
}
@EntityCustomAction(action="forum",viewKey=EntityView.VIEW_LIST)
public List<?> getForum(EntityView view, Map<String, Object> params) {
String forumId = view.getPathSegment(2);
if (forumId == null) {
forumId = (String) params.get("forumId");
if (forumId == null) {
throw new IllegalArgumentException("forumId must be set in order to get the forum info, set in params or in the URL /topic/forum/forumId");
}
}
List<?> l = getEntities(new EntityReference(ENTITY_PREFIX, ""),
new Search(CollectionResolvable.SEARCH_LOCATION_REFERENCE,"/forum/" + forumId));
return l;
}
@EntityCustomAction(action="site",viewKey=EntityView.VIEW_LIST)
public List<?> getForumsInSite(EntityView view, Map<String, Object> params) {
String siteId = view.getPathSegment(2);
if (siteId == null) {
siteId = (String) params.get("site");
if (siteId == null) {
throw new IllegalArgumentException("site must be set in order to get the forum info, set in params or in the URL /topic/site/siteId");
}
}
List<?> l = getEntities(new EntityReference(ENTITY_PREFIX, ""),
new Search(CollectionResolvable.SEARCH_LOCATION_REFERENCE,"/site/" + siteId));
return l;
}
@EntityCustomAction(action="private",viewKey=EntityView.VIEW_LIST)
public List<?> getPrivateTopicsInSite(EntityView view, Map<String, Object> params) {
String siteId = view.getPathSegment(2);
if (siteId == null) {
siteId = (String) params.get("private");
if (siteId == null) {
throw new IllegalArgumentException("siteId must be set in order to get the private topic info, set in params or in the URL /topic/private/siteId");
}
}
List<?> l = getEntities(new EntityReference(ENTITY_PREFIX, ""),
new Search(CollectionResolvable.SEARCH_LOCATION_REFERENCE,"/private/" + siteId));
return l;
}
/**
* Find a site (and optionally group) by reference
* @param locationReference
* @return a Site and optional group
* @throws IllegalArgumentException if they cannot be found for this ref
*/
public ForumSearch findLocationByReference(String locationReference) {
ForumSearch holder = new ForumSearch(locationReference);
if (locationReference.contains("/forum/")) {
// group membership
EntityReference ref = new EntityReference(locationReference);
String forumId = ref.getId();
holder.forumId = forumId;
} else if (locationReference.contains("/site/")) {
// site membership
EntityReference ref = new EntityReference(locationReference);
String siteId = ref.getId();
holder.siteId = siteId;
} else if(locationReference.contains("/private/")){
EntityReference ref = new EntityReference(locationReference);
String siteId = ref.getId();
holder.siteId = siteId;
holder.isPrivate = true;
}else{
throw new IllegalArgumentException("Do not know how to handle this location reference ("+locationReference+"), only can handle forum, site and private references");
}
return holder;
}
public static class ForumSearch{
public String forumId;
public String siteId;
public boolean isPrivate = false;
public String locationReference;
public ForumSearch(String locationReference) {
this.locationReference = locationReference;
}
}
public String[] getHandledOutputFormats() {
return new String[] { Formats.HTML, Formats.XML, Formats.JSON };
}
public String[] getHandledInputFormats() {
// TODO Auto-generated method stub
return null;
}
public UIPermissionsManager getUiPermissionsManager() {
return uiPermissionsManager;
}
public void setUiPermissionsManager(UIPermissionsManager uiPermissionsManager) {
this.uiPermissionsManager = uiPermissionsManager;
}
public MessageForumsMessageManager getMessageManager() {
return messageManager;
}
public void setMessageManager(MessageForumsMessageManager messageManager) {
this.messageManager = messageManager;
}
public PrivateMessageManager getPrivateMessageManager() {
return privateMessageManager;
}
public void setPrivateMessageManager(PrivateMessageManager privateMessageManager) {
this.privateMessageManager = privateMessageManager;
}
private String getLanguage(String navName)
{
String Tmp= "";
//getLocale( String userId )
//( userId);//SessionManager.getCurrentSessionUserId() );
// List topicsbyLocalization= new ArrayList();// only three folder supported, if need more, please modifify here
//
// topicsbyLocalization.add(local_received);
// topicsbyLocalization.add(local_sent);
// topicsbyLocalization.add(local_deleted);
if(navName.equals("Received")||navName.equals("Sent")||navName.equals("Deleted"))
{
Tmp = "en";
}
else if(navName.equals("Recibidos")||navName.equals("Enviados")||navName.equals("Borrados"))
{
Tmp ="es";
}
else//english language
{
Tmp="en";
}
return Tmp;
}
private String getPrivateMessageTypeFromContext(String navMode){
List<String> topicsbyLocalization= new ArrayList<String>();// only three folder supported, if need more, please modifify here
String local_received=rb.getString("pvt_received");
String local_sent = rb.getString("pvt_sent");
String local_deleted= rb.getString("pvt_deleted");
topicsbyLocalization.add(local_received);
topicsbyLocalization.add(local_sent);
topicsbyLocalization.add(local_deleted);
//need to add more dictionary to support more language
if (((String) topicsbyLocalization.get(0)).equalsIgnoreCase(navMode)||"Recibidos".equalsIgnoreCase(navMode)||"Received".equalsIgnoreCase(navMode)){
return typeManager.getReceivedPrivateMessageType();
}
else if (((String) topicsbyLocalization.get(1)).equalsIgnoreCase(navMode)||"Enviados".equalsIgnoreCase(navMode)||"Sent".equalsIgnoreCase(navMode)){
return typeManager.getSentPrivateMessageType();
}
else if (((String) topicsbyLocalization.get(2)).equalsIgnoreCase(navMode)||"Borrados".equalsIgnoreCase(navMode)||"Deleted".equalsIgnoreCase(navMode)){
return typeManager.getDeletedPrivateMessageType();
}
else if (PVTMSG_MODE_DRAFT.equalsIgnoreCase(navMode)){
return typeManager.getDraftPrivateMessageType();
}
else{
return typeManager.getCustomTopicType(navMode);
}
}
public MessageForumsTypeManager getTypeManager() {
return typeManager;
}
public void setTypeManager(MessageForumsTypeManager typeManager) {
this.typeManager = typeManager;
}
}