/**
* OLAT - Online Learning and Training
* http://www.olat.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
*
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),
* University of Zurich, Switzerland.
*
*/
package org.olat.restapi.repository;
import static org.olat.restapi.security.RestSecurityHelper.getIdentity;
import static org.olat.restapi.security.RestSecurityHelper.getRoles;
import static org.olat.restapi.security.RestSecurityHelper.isAuthor;
import java.io.File;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import org.olat.basesecurity.BaseSecurity;
import org.olat.basesecurity.BaseSecurityManager;
import org.olat.basesecurity.Constants;
import org.olat.basesecurity.SecurityGroup;
import org.olat.core.id.Identity;
import org.olat.core.id.Roles;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.CodeHelper;
import org.olat.core.util.FileUtils;
import org.olat.core.util.StringHelper;
import org.olat.core.util.WebappHelper;
import org.olat.fileresource.FileResourceManager;
import org.olat.fileresource.types.FileResource;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryManager;
import org.olat.resource.OLATResource;
import org.olat.resource.OLATResourceManager;
import org.olat.restapi.security.RestSecurityHelper;
import org.olat.restapi.support.ObjectFactory;
import org.olat.restapi.support.vo.RepositoryEntryVO;
/**
* Description:
* This handles the repository entries
*
*
* Initial Date: 19.05.2009
*
* @author patrickb, srosse, stephane.rosse@frentix.com
*/
@Path("repo/entries")
public class RepositoryEntriesResource {
private static final OLog log = Tracing.createLoggerFor(RepositoryEntriesResource.class);
private static final String VERSION = "1.0";
/**
* The version number of this web service
* @return
*/
@GET
@Path("version")
@Produces(MediaType.TEXT_PLAIN)
public Response getVersion() {
return Response.ok(VERSION).build();
}
/**
* List all entries in the OLAT repository
* @response.representation.200.qname {http://www.example.com}repositoryEntryVO
* @response.representation.200.mediaType text/plain, text/html, application/xml, application/json
* @response.representation.200.doc List all entries in the repository
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_REPOENTRYVOes}
* @param uriInfo The URI information
* @param httpRequest The HTTP request
* @return
*/
@GET
@Produces({MediaType.TEXT_HTML, MediaType.TEXT_PLAIN})
public Response getEntriesText(@Context UriInfo uriInfo, @Context HttpServletRequest httpRequest) {
try {
// list of courses open for everybody
Roles roles = getRoles(httpRequest);
List types = new ArrayList();
List coursRepos = RepositoryManager.getInstance().genericANDQueryWithRolesRestriction("*", "*", "*", types, roles, null);
StringBuilder sb = new StringBuilder();
sb.append("Course List\n");
for (RepositoryEntry repoE : coursRepos) {
UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
URI repoUri = baseUriBuilder.path(RepositoryEntriesResource.class)
.path(repoE.getKey().toString())
.build();
sb.append("")
.append(repoE.getDisplayname()).append("(").append(repoE.getKey()).append(")")
.append("").append("\n");
}
return Response.ok(sb.toString()).build();
} catch(Exception e) {
throw new WebApplicationException(e);
}
}
/**
* List all entries in the OLAT repository
* @response.representation.200.qname {http://www.example.com}repositoryEntryVO
* @response.representation.200.mediaType text/plain, text/html, application/xml, application/json
* @response.representation.200.doc List all entries in the repository
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_REPOENTRYVOes}
* @param httpRequest The HTTP request
* @return
*/
@GET
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response getEntries(@Context HttpServletRequest httpRequest) {
try {
// list of courses open for everybody
Roles roles = getRoles(httpRequest);
List types = new ArrayList();
List coursRepos = RepositoryManager.getInstance().genericANDQueryWithRolesRestriction("*", "*", "*", types, roles, null);
int i=0;
RepositoryEntryVO[] entryVOs = new RepositoryEntryVO[coursRepos.size()];
for (RepositoryEntry repoE : coursRepos) {
entryVOs[i++] = ObjectFactory.get(repoE);
}
return Response.ok(entryVOs).build();
} catch(Exception e) {
throw new WebApplicationException(e);
}
}
/**
* Search for repository entries, possible search attributes are name, author and type
* @response.representation.mediaType multipart/form-data
* @response.representation.doc Search for repository entries
* @response.representation.200.qname {http://www.example.com}repositoryEntryVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc Search for repository entries
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_REPOENTRYVO}
* @response.representation.401.doc The roles of the authenticated user are not sufficient
* @param type Filter by the file resource type of the repository entry
* @param author Filter by the author's username
* @param name Filter by name of repository entry
* @param myEntries Only search entries the requester owns
* @param httpRequest The HTTP request
* @return
*/
@GET
@Path("search")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response searchEntries(@QueryParam("type") String type, @QueryParam("author") @DefaultValue("*") String author,
@QueryParam("name") @DefaultValue("*") String name, @QueryParam("myentries") @DefaultValue("false") boolean myEntries,
@Context HttpServletRequest httpRequest) {
RepositoryManager rm = RepositoryManager.getInstance();
try {
List reposFound = new ArrayList();
Identity identity = getIdentity(httpRequest);
boolean restrictedType = type != null && !type.isEmpty();
// list of courses open for everybody
Roles roles = getRoles(httpRequest);
if(myEntries) {
List lstRepos = rm.queryByOwner(identity, restrictedType ? new String[] {type} : null);
boolean restrictedName = !name.equals("*");
boolean restrictedAuthor = !author.equals("*");
if(restrictedName | restrictedAuthor) {
// filter by search conditions
for(RepositoryEntry re : lstRepos) {
boolean nameOk = restrictedName ? re.getDisplayname().toLowerCase().contains(name.toLowerCase()) : true;
boolean authorOk = restrictedAuthor ? re.getInitialAuthor().toLowerCase().equals(author.toLowerCase()) : true;
if(nameOk & authorOk) reposFound.add(re);
}
} else {
if(!lstRepos.isEmpty()) reposFound.addAll(lstRepos);
}
} else {
List types = new ArrayList(1);
if(restrictedType) types.add(type);
List lstRepos = rm.genericANDQueryWithRolesRestriction(name, author, "*", restrictedType ? types : null, roles, null);
if(!lstRepos.isEmpty()) reposFound.addAll(lstRepos);
}
int i=0;
RepositoryEntryVO[] reVOs = new RepositoryEntryVO[reposFound.size()];
for (RepositoryEntry re : reposFound) {
reVOs[i++] = ObjectFactory.get(re);
}
return Response.ok(reVOs).build();
} catch(Exception e) {
throw new WebApplicationException(e);
}
}
/**
* Import a resource in the repository
* @response.representation.mediaType multipart/form-data
* @response.representation.doc The file, its name and the resourcename
* @response.representation.200.qname {http://www.example.com}repositoryEntryVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc Import the resource and return the repository entry
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_REPOENTRYVO}
* @response.representation.401.doc The roles of the authenticated user are not sufficient
* @param filename The name of the imported file
* @param file The file input stream
* @param resourcename The name of the resource
* @param displayname The display name
* @param softkey The soft key (can be null)
* @param request The HTTP request
* @return
*/
@PUT
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Consumes({MediaType.MULTIPART_FORM_DATA})
public Response putResource(@FormParam("filename") String filename, @FormParam("file") InputStream file,
@FormParam("resourcename") String resourcename, @FormParam("displayname") String displayname,
@FormParam("softkey") String softkey, @Context HttpServletRequest request) {
if(!isAuthor(request)) {
return Response.serverError().status(Status.UNAUTHORIZED).build();
}
File tmpFile = null;
long length = 0;
try {
Identity identity = RestSecurityHelper.getUserRequest(request).getIdentity();
tmpFile = getTmpFile(filename);
FileUtils.save(file, tmpFile);
FileUtils.closeSafely(file);
length = tmpFile.length();
if(length > 0) {
RepositoryEntry re = importFileResource(identity, tmpFile, resourcename, displayname, softkey);
RepositoryEntryVO vo = ObjectFactory.get(re);
return Response.ok(vo).build();
}
return Response.serverError().status(Status.NO_CONTENT).build();
} catch (Exception e) {
log.error("Error while importing a file",e);
} finally {
if(tmpFile != null && tmpFile.exists()) {
tmpFile.delete();
}
}
return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
}
private RepositoryEntry importFileResource(Identity identity, File fResource, String resourcename, String displayname,
String softkey) {
try {
FileResourceManager frm = FileResourceManager.getInstance();
FileResource newResource = frm.addFileResource(fResource, fResource.getName());
RepositoryEntry addedEntry = RepositoryManager.getInstance().createRepositoryEntryInstance(identity.getName());
addedEntry.setCanDownload(false);
addedEntry.setCanLaunch(true);
if(StringHelper.containsNonWhitespace(resourcename)) {
addedEntry.setResourcename(resourcename);
}
if(StringHelper.containsNonWhitespace(displayname)) {
addedEntry.setDisplayname(displayname);
}
if(StringHelper.containsNonWhitespace(softkey)) {
addedEntry.setSoftkey(softkey);
}
// Do set access for owner at the end, because unfinished course should be
// invisible
// addedEntry.setAccess(RepositoryEntry.ACC_OWNERS);
addedEntry.setAccess(0);// Access for nobody
// Set the resource on the repository entry and save the entry.
RepositoryManager rm = RepositoryManager.getInstance();
OLATResource ores = OLATResourceManager.getInstance().findOrPersistResourceable(newResource);
addedEntry.setOlatResource(ores);
BaseSecurity securityManager = BaseSecurityManager.getInstance();
// create security group
SecurityGroup newGroup = securityManager.createAndPersistSecurityGroup();
// member of this group may modify member's membership
securityManager.createAndPersistPolicy(newGroup, Constants.PERMISSION_ACCESS, newGroup);
// members of this group are always authors also
securityManager.createAndPersistPolicy(newGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_AUTHOR);
securityManager.addIdentityToSecurityGroup(identity, newGroup);
addedEntry.setOwnerGroup(newGroup);
// Do set access for owner at the end, because unfinished course should be
// invisible
addedEntry.setAccess(RepositoryEntry.ACC_OWNERS);
rm.saveRepositoryEntry(addedEntry);
return addedEntry;
} catch (Exception e) {
log.error("Fail to import a resource", e);
throw new WebApplicationException(e);
}
}
private File getTmpFile(String suffix) {
suffix = (suffix == null ? "" : suffix);
File tmpFile = new File(WebappHelper.getUserDataRoot() + "/tmp/", CodeHelper.getGlobalForeverUniqueID() + "_" + suffix);
FileUtils.createEmptyFile(tmpFile);
return tmpFile;
}
@Path("{repoEntryKey}")
public RepositoryEntryResource getRepositoryEntryResource() {
return new RepositoryEntryResource();
}
}