/** * 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. */ 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.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; 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.Request; 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.core.CoreSpringFactory; 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.StringHelper; import org.olat.core.util.i18n.I18nModule; import org.olat.fileresource.types.ResourceEvaluation; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; import org.olat.repository.RepositoryService; import org.olat.repository.handlers.RepositoryHandler; import org.olat.repository.handlers.RepositoryHandlerFactory; import org.olat.repository.model.SearchRepositoryEntryParameters; import org.olat.restapi.security.RestSecurityHelper; import org.olat.restapi.support.MediaTypeVariants; import org.olat.restapi.support.MultipartReader; import org.olat.restapi.support.ObjectFactory; import org.olat.restapi.support.vo.RepositoryEntryVO; import org.olat.restapi.support.vo.RepositoryEntryVOes; /** * Description:<br> * This handles the repository entries * * <P> * Initial Date: 19.05.2009 <br> * * @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); Identity identity = getIdentity(httpRequest); SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(identity, roles); List<RepositoryEntry> coursRepos = RepositoryManager.getInstance().genericANDQueryWithRolesRestriction(params, 0, -1, false); 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("<a href=\"").append(repoUri).append(">") .append(repoE.getDisplayname()).append("(").append(repoE.getKey()).append(")") .append("</a>").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 start (optional) * @param limit (optional) * @param managed (optional) * @param externalId External ID (optional) * @param externalRef External reference number (optional) * @param resourceType The resource type (CourseModule) (optional) * @param httpRequest The HTTP request * @param request The RESt request * @return */ @GET @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public Response getEntries(@QueryParam("start") @DefaultValue("0") Integer start, @QueryParam("limit") @DefaultValue("25") Integer limit, @QueryParam("managed") Boolean managed, @QueryParam("externalId") String externalId, @QueryParam("externalRef") String externalRef, @QueryParam("resourceType") String resourceType, @Context HttpServletRequest httpRequest, @Context Request request) { try { // list of courses open for everybody Roles roles = getRoles(httpRequest); Identity identity = getIdentity(httpRequest); RepositoryManager rm = RepositoryManager.getInstance(); SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(identity, roles); params.setManaged(managed); if(StringHelper.containsNonWhitespace(externalId)) { params.setExternalId(externalId); } if(StringHelper.containsNonWhitespace(externalRef)) { params.setExternalRef(externalRef); } if(StringHelper.containsNonWhitespace(resourceType)) { params.setResourceTypes(Collections.singletonList(resourceType)); } if(MediaTypeVariants.isPaged(httpRequest, request)) { int totalCount = rm.countGenericANDQueryWithRolesRestriction(params); List<RepositoryEntry> res = rm.genericANDQueryWithRolesRestriction(params, start, limit, true); RepositoryEntryVOes voes = new RepositoryEntryVOes(); voes.setRepositoryEntries(toArrayOfVOes(res)); voes.setTotalCount(totalCount); return Response.ok(voes).build(); } else { List<RepositoryEntry> res = rm.genericANDQueryWithRolesRestriction(params, 0, -1, false); RepositoryEntryVO[] voes = toArrayOfVOes(res); return Response.ok(voes).build(); } } catch(Exception e) { throw new WebApplicationException(e); } } private RepositoryEntryVO[] toArrayOfVOes(List<RepositoryEntry> coursRepos) { int i=0; RepositoryEntryVO[] entryVOs = new RepositoryEntryVO[coursRepos.size()]; for (RepositoryEntry repoE : coursRepos) { entryVOs[i++] = ObjectFactory.get(repoE); } return entryVOs; } /** * 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<RepositoryEntry> reposFound = new ArrayList<RepositoryEntry>(); Identity identity = getIdentity(httpRequest); boolean restrictedType = type != null && !type.isEmpty(); // list of courses open for everybody Roles roles = getRoles(httpRequest); if(myEntries) { List<RepositoryEntry> 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<String> types = new ArrayList<String>(1); if(restrictedType) types.add(type); SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(name, author, null, restrictedType ? types : null, identity, roles, null); List<RepositoryEntry> lstRepos = rm.genericANDQueryWithRolesRestriction(params, 0, -1, false); 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(@Context HttpServletRequest request) { if(!isAuthor(request)) { return Response.serverError().status(Status.UNAUTHORIZED).build(); } MultipartReader partsReader = null; try { Identity identity = RestSecurityHelper.getUserRequest(request).getIdentity(); partsReader = new MultipartReader(request); File tmpFile = partsReader.getFile(); long length = tmpFile.length(); if(length > 0) { Long accessRaw = partsReader.getLongValue("access"); int access = accessRaw != null ? accessRaw.intValue() : RepositoryEntry.ACC_OWNERS; String softkey = partsReader.getValue("softkey"); String resourcename = partsReader.getValue("resourcename"); String displayname = partsReader.getValue("displayname"); RepositoryEntry re = importFileResource(identity, tmpFile, resourcename, displayname, softkey, access); 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 { MultipartReader.closeQuietly(partsReader); } return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build(); } private RepositoryEntry importFileResource(Identity identity, File fResource, String resourcename, String displayname, String softkey, int access) { RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class); RepositoryHandlerFactory handlerFactory = CoreSpringFactory.getImpl(RepositoryHandlerFactory.class); try { RepositoryHandler handler = null; for(String type:handlerFactory.getSupportedTypes()) { RepositoryHandler h = handlerFactory.getRepositoryHandler(type); ResourceEvaluation eval = h.acceptImport(fResource, fResource.getName()); if(eval != null && eval.isValid()) { handler = h; break; } } RepositoryEntry addedEntry = null; if(handler != null) { Locale locale = I18nModule.getDefaultLocale(); addedEntry = handler.importResource(identity, null, displayname, "", true, locale, fResource, fResource.getName()); if(StringHelper.containsNonWhitespace(resourcename)) { addedEntry.setResourcename(resourcename); } if(StringHelper.containsNonWhitespace(softkey)) { addedEntry.setSoftkey(softkey); } if(access < RepositoryEntry.ACC_OWNERS || access > RepositoryEntry.ACC_USERS_GUESTS) { addedEntry.setAccess(RepositoryEntry.ACC_OWNERS); } else { addedEntry.setAccess(access); } addedEntry = repositoryService.update(addedEntry); } return addedEntry; } catch(Exception e) { log.error("Fail to import a resource", e); throw new WebApplicationException(e); } } @Path("{repoEntryKey}") public RepositoryEntryResource getRepositoryEntryResource() { RepositoryManager rm = RepositoryManager.getInstance(); BaseSecurity securityManager = BaseSecurityManager.getInstance(); RepositoryService repositoryService = CoreSpringFactory.getImpl(RepositoryService.class); return new RepositoryEntryResource(rm, repositoryService, securityManager); } }