/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <hr>
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* This file has been modified by the OpenOLAT community. Changes are licensed
* under the Apache 2.0 license as the original file.
* <p>
*/
package org.olat.restapi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.olat.collaboration.CollaborationTools;
import org.olat.collaboration.CollaborationToolsFactory;
import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
import org.olat.core.commons.persistence.DB;
import org.olat.core.commons.services.notifications.NotificationsManager;
import org.olat.core.commons.services.notifications.PublisherData;
import org.olat.core.commons.services.notifications.SubscriptionContext;
import org.olat.core.commons.services.notifications.restapi.vo.SubscriptionInfoVO;
import org.olat.core.commons.services.notifications.restapi.vo.SubscriptionListItemVO;
import org.olat.core.id.Identity;
import org.olat.core.util.resource.OresHelper;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.course.CourseFactory;
import org.olat.course.ICourse;
import org.olat.course.nodes.BCCourseNode;
import org.olat.course.nodes.CourseNodeConfiguration;
import org.olat.course.nodes.CourseNodeFactory;
import org.olat.course.nodes.FOCourseNode;
import org.olat.group.BusinessGroup;
import org.olat.group.BusinessGroupService;
import org.olat.modules.fo.Forum;
import org.olat.modules.fo.Message;
import org.olat.modules.fo.manager.ForumManager;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryManager;
import org.olat.restapi.repository.course.CoursesWebService;
import org.olat.test.JunitTestHelper;
import org.olat.test.OlatJerseyTestCase;
import org.olat.user.notification.UsersSubscriptionManager;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
* <h3>Description:</h3>
* Test if the web service for notifications
* <p>
* Initial Date: 26 aug. 2010 <br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*/
public class NotificationsTest extends OlatJerseyTestCase {
private static Identity userSubscriberId;
private static Identity userAndForumSubscriberId;
private static Forum forum;
private static boolean setup = false;
@Autowired
private DB dbInstance;
@Autowired
private BusinessGroupService businessGroupService;
@Autowired
private NotificationsManager notificationManager;
@Autowired
private RepositoryManager repositoryManager;
@Before
public void setUp() throws Exception {
super.setUp();
if(!setup) {
userSubscriberId = JunitTestHelper.createAndPersistIdentityAsUser("rest-notifications-test-1");
userAndForumSubscriberId = JunitTestHelper.createAndPersistIdentityAsUser("rest-notifications-test-2");
JunitTestHelper.createAndPersistIdentityAsUser("rest-notifications-test-3");
SubscriptionContext subContext = UsersSubscriptionManager.getInstance().getNewUsersSubscriptionContext();
PublisherData publisherData = UsersSubscriptionManager.getInstance().getNewUsersPublisherData();
if(!notificationManager.isSubscribed(userSubscriberId, subContext)) {
notificationManager.subscribe(userSubscriberId, subContext, publisherData);
}
if(!notificationManager.isSubscribed(userAndForumSubscriberId, subContext)) {
notificationManager.subscribe(userAndForumSubscriberId, subContext, publisherData);
}
//create a forum
forum = ForumManager.getInstance().addAForum();
Message m1 = createMessage(userSubscriberId, forum);
Assert.assertNotNull(m1);
//subscribe
SubscriptionContext forumSubContext = new SubscriptionContext("NotificationRestCourse", forum.getKey(), "2387");
PublisherData forumPdata = new PublisherData(OresHelper.calculateTypeName(Forum.class), forum.getKey().toString(), "");
if(!notificationManager.isSubscribed(userAndForumSubscriberId, forumSubContext)) {
notificationManager.subscribe(userAndForumSubscriberId, forumSubContext, forumPdata);
}
notificationManager.markPublisherNews(forumSubContext, userSubscriberId, true);
//generate one notification
String randomLogin = UUID.randomUUID().toString().replace("-", "");
JunitTestHelper.createAndPersistIdentityAsUser(randomLogin);
setup = true;
}
dbInstance.commitAndCloseSession();
}
@Test
public void testGetNotifications() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login("rest-notifications-test-1", "A6B7C8"));
URI request = UriBuilder.fromUri(getContextURI()).path("notifications").build();
HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
InputStream body = response.getEntity().getContent();
List<SubscriptionInfoVO> infos = parseUserArray(body);
assertNotNull(infos);
assertFalse(infos.isEmpty());
SubscriptionInfoVO infoVO = infos.get(0);
assertNotNull(infoVO);
assertNotNull(infoVO.getKey());
assertNotNull("User", infoVO.getType());
assertNotNull(infoVO.getTitle());
assertNotNull(infoVO.getItems());
assertFalse(infoVO.getItems().isEmpty());
conn.shutdown();
}
@Test
public void testGetUserNotifications() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login("rest-notifications-test-1", "A6B7C8"));
UriBuilder request = UriBuilder.fromUri(getContextURI()).path("notifications").queryParam("type", "User");
HttpGet method = conn.createGet(request.build(), MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
InputStream body = response.getEntity().getContent();
List<SubscriptionInfoVO> infos = parseUserArray(body);
assertNotNull(infos);
assertFalse(infos.isEmpty());
SubscriptionInfoVO infoVO = infos.get(0);
assertNotNull(infoVO);
assertNotNull(infoVO.getKey());
assertNotNull("User", infoVO.getType());
assertNotNull(infoVO.getTitle());
assertNotNull(infoVO.getItems());
assertFalse(infoVO.getItems().isEmpty());
conn.shutdown();
}
@Test
public void testGetUserForumNotifications() throws URISyntaxException, IOException {
RestConnection conn = new RestConnection();
assertTrue(conn.login(userAndForumSubscriberId.getName(), "A6B7C8"));
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.HOUR, -2);
String date = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.S").format(cal.getTime());
URI uri = conn.getContextURI().path("notifications").queryParam("date", date).build();
HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
List<SubscriptionInfoVO> infos = parseUserArray(response);
assertNotNull(infos);
assertTrue(2 <= infos.size());
conn.shutdown();
}
@Test
public void testGetUserForumNotificationsByType() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login(userAndForumSubscriberId.getName(), "A6B7C8"));
UriBuilder request = UriBuilder.fromUri(getContextURI()).path("notifications").queryParam("type", "Forum");
HttpGet method = conn.createGet(request.build(), MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
InputStream body = response.getEntity().getContent();
List<SubscriptionInfoVO> infos = parseUserArray(body);
assertNotNull(infos);
assertTrue(1 <= infos.size());
SubscriptionInfoVO infoVO = infos.get(0);
assertNotNull(infoVO);
assertNotNull(infoVO.getKey());
assertNotNull("Forum", infoVO.getType());
assertNotNull(infoVO.getTitle());
assertNotNull(infoVO.getItems());
assertFalse(infoVO.getItems().isEmpty());
conn.shutdown();
}
@Test
public void testGetNoNotifications() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login("rest-notifications-test-3", "A6B7C8"));
URI request = UriBuilder.fromUri(getContextURI()).path("/notifications").build();
HttpGet method = conn.createGet(request, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
InputStream body = response.getEntity().getContent();
List<SubscriptionInfoVO> infos = parseUserArray(body);
assertNotNull(infos);
assertTrue(infos.isEmpty());
conn.shutdown();
}
@Test
public void testGetBusinessGroupForumNotifications() throws IOException, URISyntaxException {
//create a business group with forum notifications
Identity id = JunitTestHelper.createAndPersistIdentityAsUser("rest-not-4-" + UUID.randomUUID().toString());
BusinessGroup group = businessGroupService.createBusinessGroup(id, "Notifications 1", "REST forum notifications for group", null, null, false, false, null);
CollaborationTools tools = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(group);
tools.setToolEnabled(CollaborationTools.TOOL_FORUM, true);
Forum groupForum = tools.getForum();
dbInstance.commitAndCloseSession();
//publish
String businessPath = "[BusinessGroup:" + group.getKey() + "][toolforum:0]";
SubscriptionContext forumSubContext = new SubscriptionContext("BusinessGroup", group.getKey(), "toolforum");
PublisherData forumPdata =
new PublisherData(OresHelper.calculateTypeName(Forum.class), groupForum.getKey().toString(), businessPath);
notificationManager.subscribe(id, forumSubContext, forumPdata);
Message message = createMessage(id, groupForum);
notificationManager.markPublisherNews(forumSubContext, null, true);
dbInstance.commitAndCloseSession();
//get the notification
RestConnection conn = new RestConnection();
assertTrue(conn.login(id.getName(), "A6B7C8"));
UriBuilder request = UriBuilder.fromUri(getContextURI()).path("notifications");
HttpGet method = conn.createGet(request.build(), MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
List<SubscriptionInfoVO> infos = parseUserArray(response.getEntity().getContent());
Assert.assertNotNull(infos);
Assert.assertEquals(1, infos.size());
SubscriptionInfoVO infoVO = infos.get(0);
Assert.assertNotNull(infoVO.getItems());
Assert.assertEquals(1, infoVO.getItems().size());
SubscriptionListItemVO itemVO = infoVO.getItems().get(0);
Assert.assertNotNull(itemVO);
Assert.assertEquals(group.getKey(), itemVO.getGroupKey());
Assert.assertEquals(message.getKey(), itemVO.getMessageKey());
}
@Test
public void testGetBusinessGroupFolderNotifications() throws IOException, URISyntaxException {
//create a business group with folder notifications
Identity id = JunitTestHelper.createAndPersistIdentityAsUser("rest-not-5-" + UUID.randomUUID().toString());
BusinessGroup group = businessGroupService.createBusinessGroup(id, "Notifications 2", "REST folder notifications for group", null, null, false, false, null);
CollaborationTools tools = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(group);
tools.setToolEnabled(CollaborationTools.TOOL_FOLDER, true);
String relPath = tools.getFolderRelPath();
dbInstance.commitAndCloseSession();
//publish
String businessPath = "[BusinessGroup:" + group.getKey() + "][toolfolder:0]";
SubscriptionContext folderSubContext = new SubscriptionContext("BusinessGroup", group.getKey(), "toolfolder");
PublisherData folderPdata = new PublisherData("FolderModule", relPath, businessPath);
notificationManager.subscribe(id, folderSubContext, folderPdata);
//add a file
OlatRootFolderImpl folder = tools.getSecuredFolder(group, folderSubContext, id, true);
String filename = addFile(folder);
//mark as published
notificationManager.markPublisherNews(folderSubContext, null, true);
dbInstance.commitAndCloseSession();
//get the notification
RestConnection conn = new RestConnection();
assertTrue(conn.login(id.getName(), "A6B7C8"));
UriBuilder request = UriBuilder.fromUri(getContextURI()).path("notifications");
HttpGet method = conn.createGet(request.build(), MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
List<SubscriptionInfoVO> infos = parseUserArray(response.getEntity().getContent());
Assert.assertNotNull(infos);
Assert.assertEquals(1, infos.size());
SubscriptionInfoVO infoVO = infos.get(0);
Assert.assertNotNull(infoVO.getItems());
Assert.assertEquals(1, infoVO.getItems().size());
SubscriptionListItemVO itemVO = infoVO.getItems().get(0);
Assert.assertNotNull(itemVO);
Assert.assertEquals(group.getKey(), itemVO.getGroupKey());
Assert.assertEquals("/" + filename, itemVO.getPath());
}
@Test
public void testGetCourseForumNotifications() throws IOException, URISyntaxException {
//create a course with a forum
Identity id = JunitTestHelper.createAndPersistIdentityAsAuthor("rest-not-6-" + UUID.randomUUID().toString());
ICourse course = CoursesWebService.createEmptyCourse(id, "Course forum not", "Course forum with notification", null);
dbInstance.intermediateCommit();
//create the forum
CourseNodeConfiguration newNodeConfig = CourseNodeFactory.getInstance().getCourseNodeConfiguration("fo");
FOCourseNode forumNode = (FOCourseNode)newNodeConfig.getInstance();
forumNode.setShortTitle("Forum");
forumNode.setLearningObjectives("forum objectives");
forumNode.setNoAccessExplanation("You don't have access");
Forum courseForum = forumNode.loadOrCreateForum(course.getCourseEnvironment());
course.getEditorTreeModel().addCourseNode(forumNode, course.getRunStructure().getRootNode());
CourseFactory.publishCourse(course, RepositoryEntry.ACC_USERS, false, id, Locale.ENGLISH);
dbInstance.intermediateCommit();
//add message and publisher
RepositoryEntry re = repositoryManager.lookupRepositoryEntry(course.getCourseEnvironment().getCourseGroupManager().getCourseResource(), true);
String businessPath = "[RepositoryEntry:" + re.getKey() + "][CourseNode:" + forumNode.getIdent() + "]";
SubscriptionContext forumSubContext = new SubscriptionContext("CourseModule", course.getResourceableId(), forumNode.getIdent());
PublisherData forumPdata =
new PublisherData(OresHelper.calculateTypeName(Forum.class), courseForum.getKey().toString(), businessPath);
notificationManager.subscribe(id, forumSubContext, forumPdata);
Message message = createMessage(id, courseForum);
notificationManager.markPublisherNews(forumSubContext, null, true);
dbInstance.commitAndCloseSession();
//get the notification
RestConnection conn = new RestConnection();
assertTrue(conn.login(id.getName(), "A6B7C8"));
UriBuilder request = UriBuilder.fromUri(getContextURI()).path("notifications");
HttpGet method = conn.createGet(request.build(), MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
List<SubscriptionInfoVO> infos = parseUserArray(response.getEntity().getContent());
Assert.assertNotNull(infos);
Assert.assertEquals(1, infos.size());
SubscriptionInfoVO infoVO = infos.get(0);
Assert.assertNotNull(infoVO.getItems());
Assert.assertEquals(1, infoVO.getItems().size());
SubscriptionListItemVO itemVO = infoVO.getItems().get(0);
Assert.assertNotNull(itemVO);
Assert.assertEquals(course.getResourceableId(), itemVO.getCourseKey());
Assert.assertEquals(forumNode.getIdent(), itemVO.getCourseNodeId());
Assert.assertEquals(message.getKey(), itemVO.getMessageKey());
}
@Test
public void testGetCourseFolderNotifications() throws IOException, URISyntaxException {
//create a course with a forum
Identity id = JunitTestHelper.createAndPersistIdentityAsAuthor("rest-not-7-" + UUID.randomUUID().toString());
ICourse course = CoursesWebService.createEmptyCourse(id, "Course folder not", "Course with folder and notification", null);
dbInstance.intermediateCommit();
//create the folder
CourseNodeConfiguration newNodeConfig = CourseNodeFactory.getInstance().getCourseNodeConfiguration("bc");
BCCourseNode folderNode = (BCCourseNode)newNodeConfig.getInstance();
folderNode.setShortTitle("Folder");
folderNode.setLearningObjectives("folder objectives");
folderNode.setNoAccessExplanation("You don't have access");
String relPath = BCCourseNode.getFoldernodePathRelToFolderBase(course.getCourseEnvironment(), folderNode);
VFSContainer folder = BCCourseNode.getNodeFolderContainer(folderNode, course.getCourseEnvironment());
course.getEditorTreeModel().addCourseNode(folderNode, course.getRunStructure().getRootNode());
CourseFactory.publishCourse(course, RepositoryEntry.ACC_USERS, false, id, Locale.ENGLISH);
dbInstance.intermediateCommit();
//add message and publisher
RepositoryEntry re = repositoryManager.lookupRepositoryEntry(course.getCourseEnvironment().getCourseGroupManager().getCourseResource(), true);
String businessPath = "[RepositoryEntry:" + re.getKey() + "][CourseNode:" + folderNode.getIdent() + "]";
SubscriptionContext folderSubContext = new SubscriptionContext("CourseModule", course.getResourceableId(), folderNode.getIdent());
PublisherData folderPdata = new PublisherData("FolderModule", relPath, businessPath);
notificationManager.subscribe(id, folderSubContext, folderPdata);
String filename = addFile(folder);
notificationManager.markPublisherNews(folderSubContext, null, true);
dbInstance.commitAndCloseSession();
//get the notification
RestConnection conn = new RestConnection();
assertTrue(conn.login(id.getName(), "A6B7C8"));
UriBuilder request = UriBuilder.fromUri(getContextURI()).path("notifications");
HttpGet method = conn.createGet(request.build(), MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
List<SubscriptionInfoVO> infos = parseUserArray(response.getEntity().getContent());
Assert.assertNotNull(infos);
Assert.assertEquals(1, infos.size());
SubscriptionInfoVO infoVO = infos.get(0);
Assert.assertNotNull(infoVO.getItems());
Assert.assertEquals(1, infoVO.getItems().size());
SubscriptionListItemVO itemVO = infoVO.getItems().get(0);
Assert.assertNotNull(itemVO);
Assert.assertEquals(course.getResourceableId(), itemVO.getCourseKey());
Assert.assertEquals(folderNode.getIdent(), itemVO.getCourseNodeId());
Assert.assertEquals("/" + filename, itemVO.getPath());
}
private String addFile(VFSContainer folder) throws IOException {
String filename = UUID.randomUUID().toString();
VFSLeaf file = folder.createChildLeaf(filename + ".jpg");
OutputStream out = file.getOutputStream(true);
InputStream in = UserMgmtTest.class.getResourceAsStream("portrait.jpg");
IOUtils.copy(in, out);
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
return file.getName();
}
private Message createMessage(Identity id, Forum fo) {
ForumManager fm = ForumManager.getInstance();
Message m1 = fm.createMessage(fo, id, false);
m1.setTitle("Thread-1");
m1.setBody("Body of Thread-1");
fm.addTopMessage(m1);
return m1;
}
protected List<SubscriptionInfoVO> parseUserArray(HttpResponse response) throws IOException, URISyntaxException {
InputStream body = response.getEntity().getContent();
return parseUserArray(body);
}
protected List<SubscriptionInfoVO> parseUserArray(InputStream body) {
try {
ObjectMapper mapper = new ObjectMapper(jsonFactory);
return mapper.readValue(body, new TypeReference<List<SubscriptionInfoVO>>(){/* */});
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}