/**
* 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.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.UUID;
import javax.imageio.ImageIO;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.junit.Before;
import org.junit.Test;
import org.olat.core.commons.persistence.DBFactory;
import org.olat.core.id.Identity;
import org.olat.core.util.FileUtils;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.modules.fo.Forum;
import org.olat.modules.fo.Message;
import org.olat.modules.fo.manager.ForumManager;
import org.olat.modules.fo.restapi.MessageVO;
import org.olat.modules.fo.restapi.MessageVOes;
import org.olat.modules.fo.restapi.ReplyVO;
import org.olat.restapi.support.vo.File64VO;
import org.olat.restapi.support.vo.FileVO;
import org.olat.test.JunitTestHelper;
import org.olat.test.OlatJerseyTestCase;
import org.springframework.beans.factory.annotation.Autowired;
public class ForumTest extends OlatJerseyTestCase {
private static Forum forum;
private static Message m1, m2, m3, m4 ,m5;
private static Identity id1;
@Autowired
private ForumManager forumManager;
@Before
public void setUp() throws Exception {
super.setUp();
id1 = JunitTestHelper.createAndPersistIdentityAsUser("rest-zero");
forum = forumManager.addAForum();
m1 = forumManager.createMessage(forum, id1, false);
m1.setTitle("Thread-1");
m1.setBody("Body of Thread-1");
forumManager.addTopMessage(m1);
m2 = forumManager.createMessage(forum, id1, false);
m2.setTitle("Thread-2");
m2.setBody("Body of Thread-2");
forumManager.addTopMessage(m2);
DBFactory.getInstance().intermediateCommit();
m3 = forumManager.createMessage(forum, id1, false);
m3.setTitle("Message-1.1");
m3.setBody("Body of Message-1.1");
forumManager.replyToMessage(m3, m1);
m4 = forumManager.createMessage(forum, id1, false);
m4.setTitle("Message-1.1.1");
m4.setBody("Body of Message-1.1.1");
forumManager.replyToMessage(m4, m3);
m5 = forumManager.createMessage(forum, id1, false);
m5.setTitle("Message-1.2");
m5.setBody("Body of Message-1.2");
forumManager.replyToMessage(m5, m1);
DBFactory.getInstance().intermediateCommit();
}
@Test
public void testGetThreads() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login("administrator", "openolat"));
URI uri = getForumUriBuilder().path("threads").build();
HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
InputStream body = response.getEntity().getContent();
List<MessageVO> threads = parseMessageArray(body);
assertNotNull(threads);
assertFalse(threads.isEmpty());
conn.shutdown();
}
@Test
public void testGetThreadsWithPaging() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login("administrator", "openolat"));
URI uri = getForumUriBuilder().path("threads")
.queryParam("start", "0").queryParam("limit", "2").build();
HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON + ";pagingspec=1.0", true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
MessageVOes threads = conn.parse(response, MessageVOes.class);
assertNotNull(threads);
assertNotNull(threads.getMessages());
assertTrue(threads.getTotalCount() >= 2);
conn.shutdown();
}
@Test
public void testGetThread() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login("administrator", "openolat"));
URI uri = getForumUriBuilder().path("posts").path(m1.getKey().toString()).build();
HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
InputStream body = response.getEntity().getContent();
List<MessageVO> threads = parseMessageArray(body);
assertNotNull(threads);
assertFalse(threads.isEmpty());
conn.shutdown();
}
@Test
public void testGetThreadWithPaging() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login("administrator", "openolat"));
URI uri = getForumUriBuilder().path("posts").path(m1.getKey().toString())
.queryParam("start", "0").queryParam("limit", "2").build();
HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON + ";pagingspec=1.0", true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
MessageVOes threads = conn.parse(response, MessageVOes.class);
assertNotNull(threads);
assertNotNull(threads.getMessages());
assertTrue(threads.getTotalCount() >= 2);
conn.shutdown();
}
@Test
public void testNewThread() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login("administrator", "openolat"));
URI uri = getForumUriBuilder().path("threads").queryParam("authorKey", id1.getKey())
.queryParam("title", "New thread")
.queryParam("body", "A very interesting thread").build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
MessageVO thread = conn.parse(response, MessageVO.class);
assertNotNull(thread);
assertNotNull(thread.getKey());
assertEquals(thread.getForumKey(), forum.getKey());
assertEquals(thread.getAuthorKey(), id1.getKey());
//really saved?
boolean saved = false;
ForumManager fm = ForumManager.getInstance();
List<Message> allMessages = fm.getMessagesByForum(forum);
for(Message message:allMessages) {
if(message.getKey().equals(thread.getKey())) {
saved = true;
}
}
assertTrue(saved);
conn.shutdown();
}
@Test
public void testNewMessage() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login("administrator", "openolat"));
URI uri = getForumUriBuilder().path("posts").path(m1.getKey().toString())
.queryParam("authorKey", id1.getKey())
.queryParam("title", "New message")
.queryParam("body", "A very interesting response in Thread-1").build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
MessageVO message = conn.parse(response, MessageVO.class);
assertNotNull(message);
assertNotNull(message.getKey());
assertEquals(message.getForumKey(), forum.getKey());
assertEquals(message.getAuthorKey(), id1.getKey());
assertEquals(message.getParentKey(), m1.getKey());
//really saved?
boolean saved = false;
ForumManager fm = ForumManager.getInstance();
List<Message> allMessages = fm.getMessagesByForum(forum);
for(Message msg:allMessages) {
if(msg.getKey().equals(message.getKey())) {
saved = true;
}
}
assertTrue(saved);
conn.shutdown();
}
@Test
public void testGetAttachment() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
//set a attachment
VFSContainer container = forumManager.getMessageContainer(m1.getForum().getKey(), m1.getKey());
InputStream portraitIn = CoursesElementsTest.class.getResourceAsStream("portrait.jpg");
assertNotNull(portraitIn);
VFSLeaf attachment = container.createChildLeaf(UUID.randomUUID().toString().replace("-", "") + ".jpg");
FileUtils.bcopy(portraitIn, attachment.getOutputStream(false), "");
assertTrue(conn.login("administrator", "openolat"));
URI uri = getForumUriBuilder().path("posts").path(m1.getKey().toString()).path("attachments").build();
HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
List<FileVO> files = parseFileArray(response.getEntity().getContent());
assertNotNull(files);
FileVO attachmentVO = null;
for(FileVO file:files) {
if(attachment.getName().equals(file.getTitle())) {
attachmentVO = file;
}
}
assertNotNull(attachmentVO);
URI downloadURI = new URI(attachmentVO.getHref());
HttpGet download = conn.createGet(downloadURI, MediaType.APPLICATION_JSON, true);
HttpResponse downloadResponse = conn.execute(download);
assertEquals(200, downloadResponse.getStatusLine().getStatusCode());
//String contentType = downloadResponse.getEntity().getContentType().getValue();
//doesn't work with grizzly assertEquals("image/jpeg", contentType);
conn.shutdown();
}
@Test
public void testUploadAttachment() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login(id1.getName(), "A6B7C8"));
URI uri = getForumUriBuilder().path("posts").path(m1.getKey().toString())
.queryParam("authorKey", id1.getKey())
.queryParam("title", "New message with attachment ")
.queryParam("body", "A very interesting response in Thread-1 with an attachment").build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
MessageVO message = conn.parse(response, MessageVO.class);
assertNotNull(message);
//attachment
URL portraitUrl = CoursesElementsTest.class.getResource("portrait.jpg");
assertNotNull(portraitUrl);
File portrait = new File(portraitUrl.toURI());
//upload portrait
URI attachUri = getForumUriBuilder().path("posts").path(message.getKey().toString()).path("attachments").build();
HttpPost attachMethod = conn.createPost(attachUri, MediaType.APPLICATION_JSON);
conn.addMultipart(attachMethod, "portrait.jpg", portrait);
HttpResponse attachResponse = conn.execute(attachMethod);
assertEquals(200, attachResponse.getStatusLine().getStatusCode());
//check if the file exists
ForumManager fm = ForumManager.getInstance();
VFSContainer container = fm.getMessageContainer(message.getForumKey(), message.getKey());
VFSItem uploadedFile = container.resolve("portrait.jpg");
assertNotNull(uploadedFile);
assertTrue(uploadedFile instanceof VFSLeaf);
//check if the image is still an image
VFSLeaf uploadedImage = (VFSLeaf)uploadedFile;
InputStream uploadedStream = uploadedImage.getInputStream();
BufferedImage image = ImageIO.read(uploadedStream);
FileUtils.closeSafely(uploadedStream);
assertNotNull(image);
conn.shutdown();
}
@Test
public void testUpload64Attachment() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login(id1.getName(), "A6B7C8"));
URI uri = getForumUriBuilder().path("posts").path(m1.getKey().toString())
.queryParam("authorKey", id1.getKey())
.queryParam("title", "New message with attachment ")
.queryParam("body", "A very interesting response in Thread-1 with an attachment").build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
MessageVO message = conn.parse(response, MessageVO.class);
assertNotNull(message);
//attachment
InputStream portraitStream = CoursesElementsTest.class.getResourceAsStream("portrait.jpg");
assertNotNull(portraitStream);
//upload portrait
URI attachUri = getForumUriBuilder().path("posts").path(message.getKey().toString()).path("attachments").build();
byte[] portraitBytes = IOUtils.toByteArray(portraitStream);
byte[] portrait64 = Base64.encodeBase64(portraitBytes, true);
HttpPost attachMethod = conn.createPost(attachUri, MediaType.APPLICATION_JSON);
attachMethod.addHeader("Content-Type", MediaType.APPLICATION_FORM_URLENCODED);
conn.addEntity(attachMethod, new BasicNameValuePair("file", new String(portrait64)),
new BasicNameValuePair("filename", "portrait64.jpg"));
HttpResponse attachCode = conn.execute(attachMethod);
assertEquals(200, attachCode.getStatusLine().getStatusCode());
//check if the file exists
ForumManager fm = ForumManager.getInstance();
VFSContainer container = fm.getMessageContainer(message.getForumKey(), message.getKey());
VFSItem uploadedFile = container.resolve("portrait64.jpg");
assertNotNull(uploadedFile);
assertTrue(uploadedFile instanceof VFSLeaf);
//check if the image is still an image
VFSLeaf uploadedImage = (VFSLeaf)uploadedFile;
InputStream uploadedStream = uploadedImage.getInputStream();
BufferedImage image = ImageIO.read(uploadedStream);
FileUtils.closeSafely(uploadedStream);
assertNotNull(image);
conn.shutdown();
}
@Test
public void testReplyWithTwoAttachments() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login(id1.getName(), "A6B7C8"));
ReplyVO vo = new ReplyVO();
vo.setTitle("Reply with attachment");
vo.setBody("Reply with attachment body");
File64VO[] files = new File64VO[2];
//upload portrait
InputStream portraitStream = CoursesElementsTest.class.getResourceAsStream("portrait.jpg");
assertNotNull(portraitStream);
byte[] portraitBytes = IOUtils.toByteArray(portraitStream);
byte[] portrait64 = Base64.encodeBase64(portraitBytes, true);
files[0] = new File64VO("portrait64.jpg", new String(portrait64));
//upload single page
InputStream indexStream = ForumTest.class.getResourceAsStream("singlepage.html");
assertNotNull(indexStream);
byte[] indexBytes = IOUtils.toByteArray(indexStream);
byte[] index64 = Base64.encodeBase64(indexBytes, true);
files[1] = new File64VO("singlepage64.html", new String(index64));
vo.setAttachments(files);
URI uri = getForumUriBuilder().path("posts").path(m1.getKey().toString()).build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
conn.addJsonEntity(method, vo);
method.addHeader("Accept-Language", "en");
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
MessageVO message = conn.parse(response, MessageVO.class);
assertNotNull(message);
assertNotNull(message.getAttachments());
assertEquals(2, message.getAttachments().length);
for(FileVO attachment:message.getAttachments()) {
String title = attachment.getTitle();
assertNotNull(title);
String href = attachment.getHref();
URI attachmentUri = new URI(href);
HttpGet getAttachment = conn.createGet(attachmentUri, "*/*", true);
HttpResponse attachmentCode = conn.execute(getAttachment);
assertEquals(200, attachmentCode.getStatusLine().getStatusCode());
EntityUtils.consume(attachmentCode.getEntity());
}
//check if the file exists
ForumManager fm = ForumManager.getInstance();
VFSContainer container = fm.getMessageContainer(message.getForumKey(), message.getKey());
VFSItem uploadedFile = container.resolve("portrait64.jpg");
assertNotNull(uploadedFile);
assertTrue(uploadedFile instanceof VFSLeaf);
//check if the image is still an image
VFSLeaf uploadedImage = (VFSLeaf)uploadedFile;
InputStream uploadedStream = uploadedImage.getInputStream();
BufferedImage image = ImageIO.read(uploadedStream);
FileUtils.closeSafely(uploadedStream);
assertNotNull(image);
//check if the single page exists
VFSItem uploadedPage = container.resolve("singlepage64.html");
assertNotNull(uploadedPage);
assertTrue(uploadedPage instanceof VFSLeaf);
conn.shutdown();
}
@Test
public void testUploadAttachmentWithFile64VO() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login(id1.getName(), "A6B7C8"));
URI uri = getForumUriBuilder().path("posts").path(m1.getKey().toString())
.queryParam("authorKey", id1.getKey())
.queryParam("title", "New message with attachment ")
.queryParam("body", "A very interesting response in Thread-1 with an attachment").build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
MessageVO message = conn.parse(response, MessageVO.class);
assertNotNull(message);
//attachment
InputStream portraitStream = CoursesElementsTest.class.getResourceAsStream("portrait.jpg");
assertNotNull(portraitStream);
//upload portrait
URI attachUri = getForumUriBuilder().path("posts").path(message.getKey().toString()).path("attachments").build();
HttpPut attachMethod = conn.createPut(attachUri, MediaType.APPLICATION_JSON, true);
attachMethod.addHeader("Content-Type", MediaType.APPLICATION_JSON);
byte[] portraitBytes = IOUtils.toByteArray(portraitStream);
byte[] portrait64 = Base64.encodeBase64(portraitBytes, true);
File64VO fileVo = new File64VO();
fileVo.setFile(new String(portrait64));
fileVo.setFilename("portrait64vo.jpg");
conn.addJsonEntity(attachMethod, fileVo);
HttpResponse attachCode = conn.execute(attachMethod);
assertEquals(200, attachCode.getStatusLine().getStatusCode());
//check if the file exists
ForumManager fm = ForumManager.getInstance();
VFSContainer container = fm.getMessageContainer(message.getForumKey(), message.getKey());
VFSItem uploadedFile = container.resolve("portrait64vo.jpg");
assertNotNull(uploadedFile);
assertTrue(uploadedFile instanceof VFSLeaf);
//check if the image is still an image
VFSLeaf uploadedImage = (VFSLeaf)uploadedFile;
InputStream uploadedStream = uploadedImage.getInputStream();
BufferedImage image = ImageIO.read(uploadedStream);
FileUtils.closeSafely(uploadedStream);
assertNotNull(image);
conn.shutdown();
}
@Test
public void testUploadAttachmentAndRename() throws IOException, URISyntaxException {
RestConnection conn = new RestConnection();
assertTrue(conn.login(id1.getName(), "A6B7C8"));
URI uri = getForumUriBuilder().path("posts").path(m1.getKey().toString())
.queryParam("authorKey", id1.getKey())
.queryParam("title", "New message with attachment ")
.queryParam("body", "A very interesting response in Thread-1 with an attachment").build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
MessageVO message = conn.parse(response, MessageVO.class);
assertNotNull(message);
//attachment
URL portraitUrl = CoursesElementsTest.class.getResource("portrait.jpg");
assertNotNull(portraitUrl);
File portrait = new File(portraitUrl.toURI());
//upload portrait
URI attachUri = getForumUriBuilder().path("posts").path(m1.getKey().toString()).path("attachments").build();
HttpPost attachMethod = conn.createPost(attachUri, MediaType.APPLICATION_JSON);
conn.addMultipart(attachMethod, "portrait.jpg", portrait);
HttpResponse attachCode = conn.execute(attachMethod);
assertEquals(200, attachCode.getStatusLine().getStatusCode());
EntityUtils.consume(attachCode.getEntity());
//upload portrait a second time
URI attach2Uri = getForumUriBuilder().path("posts").path(m1.getKey().toString()).path("attachments").build();
HttpPost attach2Method = conn.createPost(attach2Uri, MediaType.APPLICATION_JSON);
conn.addMultipart(attach2Method, "portrait.jpg", portrait);
HttpResponse attach2Code = conn.execute(attach2Method);
assertEquals(200, attach2Code.getStatusLine().getStatusCode());
EntityUtils.consume(attach2Code.getEntity());
// load the attachments
URI loadUri = getForumUriBuilder().path("posts").path(m1.getKey().toString()).path("attachments").build();
HttpGet loadMethod = conn.createGet(loadUri, MediaType.APPLICATION_JSON, true);
HttpResponse loadResponse = conn.execute(loadMethod);
assertEquals(200, loadResponse.getStatusLine().getStatusCode());
InputStream loadBody = loadResponse.getEntity().getContent();
List<FileVO> files = parseFileArray(loadBody);
assertNotNull(files);
assertEquals(2, files.size());
conn.shutdown();
}
private UriBuilder getForumUriBuilder() {
return UriBuilder.fromUri(getContextURI()).path("repo").path("forums").path(forum.getKey().toString());
}
protected List<MessageVO> parseMessageArray(InputStream body) {
try {
ObjectMapper mapper = new ObjectMapper(jsonFactory);
return mapper.readValue(body, new TypeReference<List<MessageVO>>(){/* */});
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}