/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <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 the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <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>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.restapi.repository;
import static org.olat.repository.ui.catalog.CatalogNodeManagerController.LOCK_TOKEN;
import static org.olat.repository.ui.catalog.CatalogNodeManagerController.lockRes;
import static org.olat.restapi.security.RestSecurityHelper.getUserRequest;
import static org.olat.restapi.security.RestSecurityHelper.isAdmin;
import static org.olat.restapi.security.RestSecurityHelper.isAuthor;
import static org.olat.restapi.support.CatalogVOFactory.get;
import static org.olat.restapi.support.CatalogVOFactory.link;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
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.PathSegment;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.olat.basesecurity.BaseSecurity;
import org.olat.basesecurity.BaseSecurityManager;
import org.olat.basesecurity.SecurityGroup;
import org.olat.core.CoreSpringFactory;
import org.olat.core.commons.persistence.DBFactory;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.translator.Translator;
import org.olat.core.id.Identity;
import org.olat.core.util.StringHelper;
import org.olat.core.util.Util;
import org.olat.core.util.coordinate.CoordinatorManager;
import org.olat.core.util.coordinate.LockResult;
import org.olat.core.util.i18n.I18nModule;
import org.olat.dispatcher.LocaleNegotiator;
import org.olat.repository.CatalogEntry;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryManager;
import org.olat.repository.manager.CatalogManager;
import org.olat.repository.ui.catalog.CatalogNodeManagerController;
import org.olat.restapi.support.MediaTypeVariants;
import org.olat.restapi.support.vo.CatalogEntryVO;
import org.olat.restapi.support.vo.CatalogEntryVOes;
import org.olat.restapi.support.vo.ErrorVO;
import org.olat.user.UserManager;
import org.olat.user.restapi.UserVO;
import org.olat.user.restapi.UserVOFactory;
/**
* Description:<br>
* A web service for the catalog
*
* <P>
* Initial Date: 5 may 2010 <br>
* @author srosse, stephane.rosse@frentix.com
*/
@Path("catalog")
public class CatalogWebService {
private static final String VERSION = "1.0";
private final CatalogManager catalogManager;
public CatalogWebService() {
catalogManager = CoreSpringFactory.getImpl(CatalogManager.class);
}
/**
* Retrieves the version of the Catalog Web Service.
* @response.representation.200.mediaType text/plain
* @response.representation.200.doc The version of this specific Web Service
* @response.representation.200.example 1.0
* @return
*/
@GET
@Path("version")
@Produces(MediaType.TEXT_PLAIN)
public Response getVersion() {
return Response.ok(VERSION).build();
}
/**
* Returns the list of root catalog entries.
* @response.representation.200.qname {http://www.example.com}catalogEntryVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The list of roots catalog entries
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVOes}
* @return The response
*/
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response getRoots(@Context HttpServletRequest httpRequest, @Context Request request) {
List<CatalogEntry> rootEntries = catalogManager.getRootCatalogEntries();
CatalogEntryVO[] entryVOes = toArray(rootEntries);
if(MediaTypeVariants.isPaged(httpRequest, request)) {
CatalogEntryVOes voes = new CatalogEntryVOes();
voes.setCatalogEntries(entryVOes);
voes.setTotalCount(1);
return Response.ok(voes).build();
} else {
return Response.ok(entryVOes).build();
}
}
/**
* Returns the metadata of the catalog entry.
* @response.representation.200.qname {http://www.example.com}catalogEntryVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The catalog entry
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO}
* @response.representation.401.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @param uriInfo The URI informations
* @param httpRequest The HTTP request
* @param request The REST request
* @return The response
*/
@GET
@Path("{path:.*}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response getCatalogEntry(@PathParam("path") List<PathSegment> path, @Context UriInfo uriInfo,
@Context HttpServletRequest httpRequest, @Context Request request) {
if(path.isEmpty()) {
return getRoots(httpRequest, request);
}
Long ceKey = getCatalogEntryKeyFromPath(path);
if(ceKey == null) {
return Response.serverError().status(Status.NOT_ACCEPTABLE).build();
}
CatalogEntry ce = catalogManager.loadCatalogEntry(ceKey);
if(ce == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
CatalogEntryVO vo = link(get(ce), uriInfo);
return Response.ok(vo).build();
}
/**
* Returns a list of catalog entries.
* @response.representation.200.qname {http://www.example.com}catalogEntryVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The list of catalog entries
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVOes}
* @response.representation.404.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @param start
* @param limit
* @param httpRequest The HTTP request
* @param request The REST request
* @return The response
*/
@GET
@Path("{path:.*}/children")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response getChildren(@PathParam("path") List<PathSegment> path, @QueryParam("start") @DefaultValue("0") Integer start,
@QueryParam("limit") @DefaultValue("25") Integer limit, @Context HttpServletRequest httpRequest, @Context Request request) {
if(path.isEmpty()) {
return getRoots(httpRequest, request);
}
Long ceKey = getCatalogEntryKeyFromPath(path);
if(ceKey == null) {
return Response.serverError().status(Status.NOT_ACCEPTABLE).build();
}
CatalogEntry ce = catalogManager.loadCatalogEntry(ceKey);
if(ce == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
if(MediaTypeVariants.isPaged(httpRequest, request)) {
int totalCount = catalogManager.countChildrenOf(ce, -1);
List<CatalogEntry> entries = catalogManager.getChildrenOf(ce, start, limit, CatalogEntry.OrderBy.name, true);
CatalogEntryVO[] entryVOes = toArray(entries);
CatalogEntryVOes voes = new CatalogEntryVOes();
voes.setTotalCount(totalCount);
voes.setCatalogEntries(entryVOes);
return Response.ok(voes).build();
} else {
List<CatalogEntry> entries = catalogManager.getChildrenOf(ce);
CatalogEntryVO[] entryVOes = toArray(entries);
return Response.ok(entryVOes).build();
}
}
private CatalogEntryVO[] toArray(List<CatalogEntry> entries) {
int count = 0;
CatalogEntryVO[] entryVOes = new CatalogEntryVO[entries.size()];
for(CatalogEntry entry:entries) {
entryVOes[count++] = get(entry);
}
return entryVOes;
}
/**
* Adds a catalog entry under the path specified in the URL.
* @response.representation.200.qname {http://www.example.com}catalogEntryVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The catalog entry
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO}
* @response.representation.401.doc Not authorized
* @response.representation.404.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @param name The name
* @param description The description
* @param type The type (leaf or node)
* @param repoEntryKey The id of the repository entry
* @param httpRquest The HTTP request
* @param uriInfo The URI informations
* @return The response
*/
@PUT
@Path("{path:.*}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response addCatalogEntry(@PathParam("path") List<PathSegment> path,
@QueryParam("name") String name, @QueryParam("description") String description,
@QueryParam("type") Integer type, @QueryParam("repoEntryKey") Long repoEntryKey,
@Context HttpServletRequest httpRequest,
@Context UriInfo uriInfo) {
CatalogEntryVO entryVo = new CatalogEntryVO();
entryVo.setName(name);
entryVo.setDescription(description);
if(type != null) {
entryVo.setType(type.intValue());
}
entryVo.setRepositoryEntryKey(repoEntryKey);
return addCatalogEntry(path, entryVo, httpRequest, uriInfo);
}
/**
* Adds a catalog entry under the path specified in the URL.
* @response.representation.qname {http://www.example.com}catalogEntryVO
* @response.representation.mediaType application/xml, application/json
* @response.representation.doc The catalog entry
* @response.representation.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO}
* @response.representation.200.qname {http://www.example.com}catalogEntryVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The list of catalog entry
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO}
* @response.representation.401.doc Not authorized
* @response.representation.404.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @param entryVo The catalog entry
* @param httpRquest The HTTP request
* @param uriInfo The URI informations
* @return The response
*/
@PUT
@Path("{path:.*}")
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response addCatalogEntry(@PathParam("path") List<PathSegment> path, CatalogEntryVO entryVo,
@Context HttpServletRequest httpRequest, @Context UriInfo uriInfo) {
if(!isAuthor(httpRequest)) {
return Response.serverError().status(Status.UNAUTHORIZED).build();
}
Long parentKey = getCatalogEntryKeyFromPath(path);
if(parentKey == null) {
return Response.serverError().status(Status.NOT_ACCEPTABLE).build();
}
CatalogEntry parent = catalogManager.loadCatalogEntry(parentKey);
if(parent == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
int type = guessType(entryVo);
if(type == CatalogEntry.TYPE_NODE && !canAdminSubTree(parent, httpRequest)) {
return Response.serverError().status(Status.UNAUTHORIZED).build();
}
RepositoryEntry re = null;
if(entryVo.getRepositoryEntryKey() != null) {
re = RepositoryManager.getInstance().lookupRepositoryEntry(entryVo.getRepositoryEntryKey());
if(re == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
}
Identity id = getUserRequest(httpRequest).getIdentity();
LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, id, LOCK_TOKEN);
if (!lock.isSuccess()) {
return getLockedResponse(lock, httpRequest);
}
CatalogEntry ce = null;
try {
ce = catalogManager.createCatalogEntry();
ce.setType(guessType(entryVo));
ce.setName(entryVo.getName());
ce.setDescription(entryVo.getDescription());
ce.setOwnerGroup(BaseSecurityManager.getInstance().createAndPersistSecurityGroup());
if(re != null) {
ce.setRepositoryEntry(re);
}
catalogManager.addCatalogEntry(parent, ce);
} catch (Exception e) {
throw new WebApplicationException(e);
} finally {
CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(lock);
}
CatalogEntryVO newEntryVo = link(get(ce), uriInfo);
return Response.ok(newEntryVo).build();
}
/**
* Updates the catalog entry under the path specified in the URL.
* @response.representation.200.qname {http://www.example.com}catalogEntryVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The catalog entry
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO}
* @response.representation.401.doc Not authorized
* @response.representation.404.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @param name The name
* @param description The description
* @param newParentKey The parent key to move the entry (optional)
* @param httpRquest The HTTP request
* @param uriInfo The URI informations
* @return The response
*/
@POST
@Path("{path:.*}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response updatePostCatalogEntry(@PathParam("path") List<PathSegment> path,
@FormParam("name") String name, @FormParam("description") String description,
@FormParam("newParentKey") Long newParentKey,//fxdiff FXOLAT-122: course management
@Context HttpServletRequest httpRequest, @Context UriInfo uriInfo) {
CatalogEntryVO entryVo = new CatalogEntryVO();
entryVo.setName(name);
entryVo.setDescription(description);
return updateCatalogEntry(path, entryVo, newParentKey, httpRequest, uriInfo);
}
/**
* Updates the catalog entry with the path specified in the URL.
* @response.representation.200.qname {http://www.example.com}catalogEntryVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The catalog entry
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO}
* @response.representation.401.doc Not authorized
* @response.representation.404.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @param id The id of the catalog entry
* @param name The name
* @param description The description
* @param newParentKey The parent key to move the entry (optional)
* @param httpRquest The HTTP request
* @param uriInfo The URI informations
* @return The response
*/
@POST
@Path("{path:.*}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response updateCatalogEntry(@PathParam("path") List<PathSegment> path,
@QueryParam("name") String name, @QueryParam("description") String description,
@QueryParam("newParentKey") Long newParentKey,//fxdiff FXOLAT-122: course management
@Context HttpServletRequest httpRequest, @Context UriInfo uriInfo) {
CatalogEntryVO entryVo = new CatalogEntryVO();
entryVo.setName(name);
entryVo.setDescription(description);
return updateCatalogEntry(path, entryVo, newParentKey, httpRequest, uriInfo);
}
/**
* Updates the catalog entry with the path specified in the URL.
* @response.representation.200.qname {http://www.example.com}catalogEntryVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The catalog entry
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO}
* @response.representation.401.doc Not authorized
* @response.representation.404.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @param entryVo The catalog entry
* @param newParentKey The parent key to move the entry (optional)
* @param httpRquest The HTTP request
* @param uriInfo The URI informations
* @return The response
*/
@POST
@Path("{path:.*}")
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response updateCatalogEntry(@PathParam("path") List<PathSegment> path,
CatalogEntryVO entryVo, @QueryParam("newParentKey") Long newParentKey, @Context HttpServletRequest httpRequest, @Context UriInfo uriInfo) {
if(!isAuthor(httpRequest)) {
return Response.serverError().status(Status.UNAUTHORIZED).build();
}
Long key = getCatalogEntryKeyFromPath(path);
if(key == null) {
return Response.serverError().status(Status.NOT_ACCEPTABLE).build();
}
CatalogEntry ce = catalogManager.loadCatalogEntry(key);
if(ce.getType() == CatalogEntry.TYPE_NODE) {
//check if can admin category
if(!canAdminSubTree(ce, httpRequest)) {
return Response.serverError().status(Status.UNAUTHORIZED).build();
}
}
//fxdiff FXOLAT-122: course management
CatalogEntry newParent = null;
if(newParentKey != null) {
newParent = catalogManager.loadCatalogEntry(newParentKey);
if(newParent.getType() == CatalogEntry.TYPE_NODE) {
//check if can admin category
if(!canAdminSubTree(newParent, httpRequest)) {
return Response.serverError().status(Status.UNAUTHORIZED).build();
}
}
}
Identity id = getUserRequest(httpRequest).getIdentity();
LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, id, LOCK_TOKEN);
if (!lock.isSuccess()) {
return getLockedResponse(lock, httpRequest);
}
try {
ce = catalogManager.loadCatalogEntry(ce);
if(ce == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
//only update if needed
if(StringHelper.containsNonWhitespace(entryVo.getName())) {
ce.setName(entryVo.getName());
}
if(StringHelper.containsNonWhitespace(entryVo.getDescription())) {
ce.setDescription(entryVo.getDescription());
}
if(entryVo.getType() != null) {
ce.setType(guessType(entryVo));
}
catalogManager.updateCatalogEntry(ce);
if(newParent != null) {
catalogManager.moveCatalogEntry(ce, newParent);
}
} catch (Exception e) {
throw new WebApplicationException(e);
} finally {
CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(lock);
}
CatalogEntryVO newEntryVo = link(get(ce), uriInfo);
return Response.ok(newEntryVo).build();
}
/**
* Deletes the catalog entry with the path specified in the URL.
* @response.representation.200.qname {http://www.example.com}catalogEntryVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The catalog entry
* @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_CATALOGENTRYVO}
* @response.representation.401.doc Not authorized
* @response.representation.404.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @param httpRquest The HTTP request
* @return The response
*/
@DELETE
@Path("{path:.*}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response deleteCatalogEntry(@PathParam("path") List<PathSegment> path, @Context HttpServletRequest httpRequest) {
Long key = getCatalogEntryKeyFromPath(path);
if(key == null) {
return Response.serverError().status(Status.NOT_ACCEPTABLE).build();
}
CatalogEntry ce = catalogManager.loadCatalogEntry(key);
if(ce == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
if(!canAdminSubTree(ce, httpRequest)) {
return Response.serverError().status(Status.UNAUTHORIZED).build();
}
Identity id = getUserRequest(httpRequest).getIdentity();
LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, id, LOCK_TOKEN);
if (!lock.isSuccess()) {
return getLockedResponse(lock, httpRequest);
}
try {
catalogManager.deleteCatalogEntry(ce);
} catch(Exception e) {
throw new WebApplicationException(e);
} finally {
CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(lock);
}
return Response.ok().build();
}
/**
* Get the owners of the local sub tree
* @response.representation.200.qname {http://www.example.com}userVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The catalog entry
* @response.representation.200.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
* @response.representation.401.doc Not authorized
* @response.representation.404.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @param httpRquest The HTTP request
* @return The response
*/
@GET
@Path("{path:.*}/owners")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response getOwners(@PathParam("path") List<PathSegment> path, @Context HttpServletRequest httpRequest) {
Long key = getCatalogEntryKeyFromPath(path);
if(key == null) {
return Response.serverError().status(Status.NOT_ACCEPTABLE).build();
}
CatalogEntry ce = catalogManager.loadCatalogEntry(key);
if(ce == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
if(!isAuthor(httpRequest) && !canAdminSubTree(ce, httpRequest)) {
return Response.serverError().status(Status.UNAUTHORIZED).build();
}
SecurityGroup sg = ce.getOwnerGroup();
if(sg == null) {
return Response.ok(new UserVO[0]).build();
}
List<Identity> ids = BaseSecurityManager.getInstance().getIdentitiesOfSecurityGroup(sg);
int count = 0;
UserVO[] voes = new UserVO[ids.size()];
for(Identity id:ids) {
voes[count++] = UserVOFactory.get(id);
}
return Response.ok(voes).build();
}
/**
* Retrieves data of an owner of the local sub tree
* @response.representation.200.qname {http://www.example.com}userVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The catalog entry
* @response.representation.200.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
* @response.representation.401.doc Not authorized
* @response.representation.404.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @Param identityKey The id of the user
* @param httpRquest The HTTP request
* @return The response
*/
@GET
@Path("{path:.*}/owners/{identityKey}")
public Response getOwner(@PathParam("path") List<PathSegment> path, @PathParam("identityKey") Long identityKey,
@Context HttpServletRequest httpRequest) {
Long key = getCatalogEntryKeyFromPath(path);
if(key == null) {
return Response.serverError().status(Status.NOT_ACCEPTABLE).build();
}
CatalogEntry ce = catalogManager.loadCatalogEntry(key);
if(ce == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
if(!isAuthor(httpRequest) && !canAdminSubTree(ce, httpRequest)) {
return Response.serverError().status(Status.UNAUTHORIZED).build();
}
SecurityGroup sg = ce.getOwnerGroup();
if(sg == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
List<Identity> ids = BaseSecurityManager.getInstance().getIdentitiesOfSecurityGroup(sg);
UserVO vo = null;
for(Identity id:ids) {
if(id.getKey().equals(identityKey)) {
vo = UserVOFactory.get(id);
break;
}
}
if(vo == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
return Response.ok(vo).build();
}
/**
* Add an owner of the local sub tree
* @response.representation.200.qname {http://www.example.com}userVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The catalog entry
* @response.representation.200.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
* @response.representation.401.doc Not authorized
* @response.representation.404.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @param identityKey The id of the user
* @param httpRquest The HTTP request
* @return The response
*/
@PUT
@Path("{path:.*}/owners/{identityKey}")
public Response addOwner(@PathParam("path") List<PathSegment> path, @PathParam("identityKey") Long identityKey,
@Context HttpServletRequest httpRequest) {
Long key = getCatalogEntryKeyFromPath(path);
if(key == null) {
return Response.serverError().status(Status.NOT_ACCEPTABLE).build();
}
CatalogEntry ce = catalogManager.loadCatalogEntry(key);
if(ce == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
if(!isAuthor(httpRequest) && !canAdminSubTree(ce, httpRequest)) {
return Response.serverError().status(Status.UNAUTHORIZED).build();
}
BaseSecurity securityManager = BaseSecurityManager.getInstance();
Identity identity = securityManager.loadIdentityByKey(identityKey, false);
if(identity == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
Identity id = getUserRequest(httpRequest).getIdentity();
LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, id, LOCK_TOKEN);
if (!lock.isSuccess()) {
return getLockedResponse(lock, httpRequest);
}
try {
SecurityGroup sg = ce.getOwnerGroup();
if(sg == null) {
ce.setOwnerGroup(securityManager.createAndPersistSecurityGroup());
DBFactory.getInstance().intermediateCommit();
}
securityManager.addIdentityToSecurityGroup(identity, ce.getOwnerGroup());
} catch(Exception e) {
throw new WebApplicationException(e);
} finally {
CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(lock);
}
return Response.ok().build();
}
/**
* Remove an owner of the local sub tree
* @response.representation.200.qname {http://www.example.com}userVO
* @response.representation.200.mediaType application/xml, application/json
* @response.representation.200.doc The catalog entry
* @response.representation.200.example {@link org.olat.user.restapi.Examples#SAMPLE_USERVOes}
* @response.representation.401.doc Not authorized
* @response.representation.404.doc The path could not be resolved to a valid catalog entry
* @param path The path
* @param identityKey The id of the user
* @param httpRquest The HTTP request
* @return The response
*/
@DELETE
@Path("{path:.*}/owners/{identityKey}")
public Response removeOwner(@PathParam("path") List<PathSegment> path, @PathParam("identityKey") Long identityKey,
@Context HttpServletRequest httpRequest) {
Long key = getCatalogEntryKeyFromPath(path);
if(key == null) {
return Response.serverError().status(Status.NOT_ACCEPTABLE).build();
}
CatalogEntry ce = catalogManager.loadCatalogEntry(key);
if(ce == null) {
return Response.serverError().status(Status.NOT_FOUND).build();
}
if(!isAuthor(httpRequest) && !canAdminSubTree(ce, httpRequest)) {
return Response.serverError().status(Status.UNAUTHORIZED).build();
}
BaseSecurity securityManager = BaseSecurityManager.getInstance();
Identity identity = securityManager.loadIdentityByKey(identityKey, false);
if(identity == null) {
return Response.ok().build();
}
SecurityGroup sg = ce.getOwnerGroup();
if(sg == null) {
return Response.ok().build();
}
Identity id = getUserRequest(httpRequest).getIdentity();
LockResult lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(lockRes, id, LOCK_TOKEN);
if (!lock.isSuccess()) {
return getLockedResponse(lock, httpRequest);
}
try {
securityManager.removeIdentityFromSecurityGroup(identity, ce.getOwnerGroup());
} catch(Exception e) {
throw new WebApplicationException(e);
} finally {
CoordinatorManager.getInstance().getCoordinator().getLocker().releaseLock(lock);
}
return Response.ok().build();
}
private Response getLockedResponse(LockResult lock, HttpServletRequest request) {
Locale locale = null;
UserRequest ureq = getUserRequest(request);
if(ureq != null) {
locale = LocaleNegotiator.getPreferedLocale(ureq);
}
if(locale == null) {
locale = I18nModule.getDefaultLocale();
}
Translator translator = Util.createPackageTranslator(CatalogNodeManagerController.class, locale);
String ownerName = CoreSpringFactory.getImpl(UserManager.class).getUserDisplayName(lock.getOwner());
String translation = translator.translate("catalog.locked.by", new String[]{ ownerName });
ErrorVO vo = new ErrorVO("org.olat.catalog.ui","catalog.locked.by",translation);
ErrorVO[] voes = new ErrorVO[]{vo};
return Response.ok(voes).status(Status.UNAUTHORIZED).build();
}
private Long getCatalogEntryKeyFromPath(List<PathSegment> path) {
PathSegment lastPath = path.get(path.size() - 1);
Long key = null;
try {
key = new Long(lastPath.getPath());
} catch (NumberFormatException e) {
key = null;
}
return key;
}
private boolean canAdminSubTree(CatalogEntry ce, HttpServletRequest httpRequest) {
if(isAdmin(httpRequest)) return true;
Identity identity = getUserRequest(httpRequest).getIdentity();
SecurityGroup owners = ce.getOwnerGroup();
if (owners != null && BaseSecurityManager.getInstance().isIdentityInSecurityGroup(identity, owners)) {
return true;
}
return false;
}
private int guessType(CatalogEntryVO vo) {
Integer type = vo.getType();
if(type == null) {
if(vo.getRepositoryEntryKey() == null) {
return CatalogEntry.TYPE_NODE;
}
return CatalogEntry.TYPE_LEAF;
}
return type.intValue();
}
}