/**
* 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.assertNotNull;
import static org.junit.Assert.assertTrue;
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.Date;
import java.util.List;
import java.util.UUID;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import org.apache.http.HttpEntity;
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.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.util.EntityUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.olat.basesecurity.BaseSecurityManager;
import org.olat.basesecurity.GroupRoles;
import org.olat.core.commons.persistence.DB;
import org.olat.core.id.Identity;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.StringHelper;
import org.olat.course.CourseFactory;
import org.olat.course.ICourse;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryEntryRelationType;
import org.olat.repository.RepositoryManager;
import org.olat.repository.manager.RepositoryEntryLifecycleDAO;
import org.olat.repository.manager.RepositoryEntryRelationDAO;
import org.olat.repository.model.RepositoryEntryLifecycle;
import org.olat.restapi.repository.course.CoursesWebService;
import org.olat.restapi.support.vo.CourseVO;
import org.olat.restapi.support.vo.CourseVOes;
import org.olat.test.JunitTestHelper;
import org.olat.test.OlatJerseyTestCase;
import org.springframework.beans.factory.annotation.Autowired;
public class CoursesTest extends OlatJerseyTestCase {
private static final OLog log = Tracing.createLoggerFor(CoursesTest.class);
private Identity admin;
private ICourse course1, course2, course3;
private RepositoryEntry re1, re2, re3;
private String externalId, externalRef;
private String externalId3;
private RestConnection conn;
@Autowired
private DB dbInstance;
@Autowired
private RepositoryManager repositoryManager;
@Autowired
private RepositoryEntryLifecycleDAO reLifecycleDao;
@Autowired
private RepositoryEntryRelationDAO repositoryEntryRelationDao;
/**
* SetUp is called before each test.
*/
@Before
public void setUp() throws Exception {
super.setUp();
conn = new RestConnection();
try {
// create course and persist as OLATResourceImpl
admin = BaseSecurityManager.getInstance().findIdentityByName("administrator");
course1 = CoursesWebService.createEmptyCourse(admin, "courses1", "courses1 long name", null, null, null, RepositoryEntry.ACC_OWNERS, false, null, null, null, null, null, null);
externalId = UUID.randomUUID().toString();
externalRef = UUID.randomUUID().toString();
course2 = CoursesWebService.createEmptyCourse(admin, "courses2", "courses2 long name", null, null, null, RepositoryEntry.ACC_OWNERS, false, null, null, externalId, externalRef, "all", null);
dbInstance.commitAndCloseSession();
re1 = repositoryManager.lookupRepositoryEntry(course1, false);
re2 = repositoryManager.lookupRepositoryEntry(course2, false);
externalId3 = UUID.randomUUID().toString();
course3 = CoursesWebService.createEmptyCourse(admin, "courses3", "courses3 long name", null, null, null, RepositoryEntry.ACC_OWNERS, false, null, null, externalId3, null, "all", null);
re3 = repositoryManager.lookupRepositoryEntry(course3, false);
RepositoryEntryLifecycle lifecycle3 = reLifecycleDao.create("course3 lifecycle", UUID.randomUUID().toString(), true, new Date(), new Date());
dbInstance.commit();
re3.setLifecycle(lifecycle3);
re3 = dbInstance.getCurrentEntityManager().merge(re3);
dbInstance.commitAndCloseSession();
} catch (Exception e) {
log.error("Exception in setUp(): " + e);
}
}
@After
public void tearDown() throws Exception {
try {
if(conn != null) {
conn.shutdown();
}
} catch (Exception e) {
log.error("", e);
throw e;
}
}
@Test
public void testGetCourses() throws IOException, URISyntaxException {
assertTrue(conn.login("administrator", "openolat"));
URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").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<CourseVO> courses = parseCourseArray(body);
assertNotNull(courses);
assertTrue(courses.size() >= 2);
boolean vo1 = false;
boolean vo2 = false;
for(CourseVO course:courses) {
Long repoEntryKey = course.getRepoEntryKey();
if(repoEntryKey != null && re1.getKey().equals(repoEntryKey)) {
vo1 = true;
Assert.assertEquals("courses1", course.getTitle());
}
if(repoEntryKey != null && re2.getKey().equals(repoEntryKey)) {
vo2 = true;
Assert.assertEquals("courses2", course.getTitle());
}
}
Assert.assertTrue(vo1);
Assert.assertTrue(vo2);
}
@Test
public void testGetCourses_searchExternalID() throws IOException, URISyntaxException {
assertTrue(conn.login("administrator", "openolat"));
URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").queryParam("externalId", externalId).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<CourseVO> courses = parseCourseArray(body);
assertNotNull(courses);
assertTrue(courses.size() >= 1);
CourseVO vo = null;
for(CourseVO course:courses) {
if(externalId.equals(course.getExternalId())) {
vo = course;
}
}
assertNotNull(vo);
assertEquals(vo.getKey(), course2.getResourceableId());
}
@Test
public void testGetCourses_searchExternalID_withLifecycle() throws IOException, URISyntaxException {
assertTrue(conn.login("administrator", "openolat"));
URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").queryParam("externalId", externalId3).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<CourseVO> courses = parseCourseArray(body);
assertNotNull("Course list cannot be null", courses);
assertEquals(1, courses.size());
CourseVO vo = courses.get(0);
assertNotNull("Course cannot be null", vo);
assertEquals(vo.getKey(), course3.getResourceableId());
assertNotNull("Has a lifecycle", vo.getLifecycle());
assertNotNull("Life cycle has a soft key", vo.getLifecycle().getSoftkey());
}
@Test
public void testGetCourses_searchExternalRef() throws IOException, URISyntaxException {
assertTrue(conn.login("administrator", "openolat"));
URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").queryParam("externalRef", externalRef).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<CourseVO> courses = parseCourseArray(body);
assertNotNull(courses);
assertTrue(courses.size() >= 1);
CourseVO vo = null;
for(CourseVO course:courses) {
if(externalRef.equals(course.getExternalRef())) {
vo = course;
}
}
assertNotNull(vo);
assertEquals(vo.getKey(), course2.getResourceableId());
}
@Test
public void testGetCourses_managed() throws IOException, URISyntaxException {
assertTrue(conn.login("administrator", "openolat"));
URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").queryParam("managed", "true").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<CourseVO> courses = parseCourseArray(body);
assertNotNull(courses);
assertTrue(courses.size() >= 1);
for(CourseVO course:courses) {
boolean managed = StringHelper.containsNonWhitespace(course.getManagedFlags());
Assert.assertTrue(managed);
}
}
@Test
public void testGetCourses_notManaged() throws IOException, URISyntaxException {
assertTrue(conn.login("administrator", "openolat"));
URI request = UriBuilder.fromUri(getContextURI()).path("/repo/courses").queryParam("managed", "false").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<CourseVO> courses = parseCourseArray(body);
assertNotNull(courses);
assertTrue(courses.size() >= 1);
for(CourseVO course:courses) {
boolean managed = StringHelper.containsNonWhitespace(course.getManagedFlags());
Assert.assertFalse(managed);
}
}
@Test
public void testGetCoursesWithPaging() throws IOException, URISyntaxException {
assertTrue(conn.login("administrator", "openolat"));
URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
.queryParam("start", "0").queryParam("limit", "1").build();
HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON + ";pagingspec=1.0", true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
CourseVOes courses = conn.parse(response, CourseVOes.class);
assertNotNull(courses);
assertNotNull(courses.getCourses());
assertEquals(1, courses.getCourses().length);
}
@Test
public void testCreateEmptyCourse() throws IOException, URISyntaxException {
assertTrue(conn.login("administrator", "openolat"));
URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
.queryParam("shortTitle", "course3").queryParam("title", "course3 long name").build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertEquals(200, response.getStatusLine().getStatusCode());
CourseVO course = conn.parse(response, CourseVO.class);
assertNotNull(course);
assertEquals("course3", course.getTitle());
//check repository entry
RepositoryEntry re = repositoryManager.lookupRepositoryEntry(course.getRepoEntryKey());
assertNotNull(re);
assertNotNull(re.getOlatResource());
}
@Test
public void testCreateEmpty_withoutAuthorCourse() throws IOException, URISyntaxException {
assertTrue(conn.login("administrator", "openolat"));
URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
.queryParam("shortTitle", "Course without author")
.queryParam("title", "Course without author")
.queryParam("setAuthor", "false").build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
CourseVO courseVo = conn.parse(response, CourseVO.class);
Assert.assertNotNull(courseVo);
Assert.assertEquals("Course without author", courseVo.getTitle());
// load repository entry
RepositoryEntry re = repositoryManager.lookupRepositoryEntry(courseVo.getRepoEntryKey());
Assert.assertNotNull(re);
Assert.assertNotNull(re.getOlatResource());
Assert.assertEquals("Course without author", re.getDisplayname());
// load the course
ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
Assert.assertNotNull(course);
Assert.assertEquals("Course without author", course.getCourseTitle());
Assert.assertEquals(re, course.getCourseEnvironment().getCourseGroupManager().getCourseEntry());
// check the list of owners
List<Identity> owners = repositoryEntryRelationDao.getMembers(re, RepositoryEntryRelationType.both, GroupRoles.owner.name());
Assert.assertNotNull(owners);
Assert.assertTrue(owners.isEmpty());
}
@Test
public void testCreateEmpty_withInitialAuthor() throws IOException, URISyntaxException {
Identity adhocAuthor = JunitTestHelper.createAndPersistIdentityAsRndUser("adhoc-author");
dbInstance.commit();
assertTrue(conn.login("administrator", "openolat"));
URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
.queryParam("shortTitle", "Course without author")
.queryParam("title", "Course without author")
.queryParam("initialAuthor", adhocAuthor.getKey().toString())
.build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
CourseVO courseVo = conn.parse(response, CourseVO.class);
Assert.assertNotNull(courseVo);
Assert.assertEquals("Course without author", courseVo.getTitle());
// load repository entry
RepositoryEntry re = repositoryManager.lookupRepositoryEntry(courseVo.getRepoEntryKey());
Assert.assertNotNull(re);
Assert.assertNotNull(re.getOlatResource());
Assert.assertEquals("Course without author", re.getDisplayname());
// load the course
ICourse course = CourseFactory.loadCourse(re.getOlatResource().getResourceableId());
Assert.assertNotNull(course);
Assert.assertEquals("Course without author", course.getCourseTitle());
Assert.assertEquals(re, course.getCourseEnvironment().getCourseGroupManager().getCourseEntry());
// check the list of owners
List<Identity> owners = repositoryEntryRelationDao.getMembers(re, RepositoryEntryRelationType.both, GroupRoles.owner.name());
Assert.assertNotNull(owners);
Assert.assertEquals(1, owners.size());
Assert.assertEquals(adhocAuthor, owners.get(0));
}
@Test
public void testImportCourse() throws IOException, URISyntaxException {
URL cpUrl = CoursesTest.class.getResource("Course_with_blog.zip");
assertNotNull(cpUrl);
File cp = new File(cpUrl.toURI());
assertTrue(conn.login("administrator", "openolat"));
URI request = UriBuilder.fromUri(getContextURI()).path("repo/courses").build();
HttpPost method = conn.createPost(request, MediaType.APPLICATION_JSON);
String softKey = UUID.randomUUID().toString().replace("-", "").substring(0, 30);
HttpEntity entity = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.addBinaryBody("file", cp, ContentType.APPLICATION_OCTET_STREAM, cp.getName())
.addTextBody("filename", "Very_small_course.zip")
.addTextBody("foldername", "New folder 1 2 3")
.addTextBody("resourcename", "Very small course")
.addTextBody("displayname", "Very small course")
.addTextBody("access", "3")
.addTextBody("softkey", softKey)
.build();
method.setEntity(entity);
HttpResponse response = conn.execute(method);
assertTrue(response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 201);
CourseVO vo = conn.parse(response, CourseVO.class);
assertNotNull(vo);
assertNotNull(vo.getRepoEntryKey());
assertNotNull(vo.getKey());
Long repoKey = vo.getRepoEntryKey();
RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(repoKey);
assertNotNull(re);
assertNotNull(re.getOlatResource());
assertEquals("Very small course", re.getDisplayname());
assertEquals(softKey, re.getSoftkey());
}
@Test
public void testCopyCourse() throws IOException, URISyntaxException {
Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("author-5");
RepositoryEntry entry = JunitTestHelper.deployBasicCourse(author);
Assert.assertNotNull(entry);
conn = new RestConnection();
Assert.assertTrue(conn.login("administrator", "openolat"));
URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
.queryParam("shortTitle", "Course copy")
.queryParam("title", "Course copy")
.queryParam("initialAuthor", author.getKey().toString())
.queryParam("copyFrom", entry.getKey().toString())
.build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertTrue(response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 201);
CourseVO vo = conn.parse(response, CourseVO.class);
assertNotNull(vo);
assertNotNull(vo.getRepoEntryKey());
assertNotNull(vo.getKey());
}
@Test
public void testCopyCourse_unkownCourse() throws IOException, URISyntaxException {
Identity author = JunitTestHelper.createAndPersistIdentityAsAuthor("author-5");
RepositoryEntry entry = JunitTestHelper.deployBasicCourse(author);
Assert.assertNotNull(entry);
conn = new RestConnection();
Assert.assertTrue(conn.login("administrator", "openolat"));
URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
.queryParam("shortTitle", "Course copy")
.queryParam("title", "Course copy")
.queryParam("initialAuthor", author.getKey().toString())
.queryParam("copyFrom", "-2")
.build();
HttpPut method = conn.createPut(uri, MediaType.APPLICATION_JSON, true);
HttpResponse response = conn.execute(method);
assertTrue(response.getStatusLine().getStatusCode() == 404);
EntityUtils.consume(response.getEntity());
}
protected List<CourseVO> parseCourseArray(InputStream body) {
try {
ObjectMapper mapper = new ObjectMapper(jsonFactory);
return mapper.readValue(body, new TypeReference<List<CourseVO>>(){/* */});
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}