/**
*
*/
package org.ihtsdo.otf.refset.controller;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
import static org.ihtsdo.otf.refset.common.Utility.getUserDetails;
import static org.ihtsdo.otf.refset.common.Utility.getResult;
import java.nio.file.AccessDeniedException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Resource;
import org.ihtsdo.otf.refset.common.Meta;
import org.ihtsdo.otf.refset.common.Result;
import org.ihtsdo.otf.refset.domain.Member;
import org.ihtsdo.otf.refset.domain.MemberValidator;
import org.ihtsdo.otf.refset.domain.Refset;
import org.ihtsdo.otf.refset.domain.RefsetValidator;
import org.ihtsdo.otf.refset.exception.ValidationException;
import org.ihtsdo.otf.refset.service.RefsetAuthoringService;
import org.ihtsdo.otf.refset.service.RefsetBrowseService;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.Assert;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
/**
* Controller class to facilitate {@link Refset} authoring.It also check required authorization
*
*/
@RestController
@Api(value="RefsetAuthoring", description="Service to author refset and their member details", position = 1)
@RequestMapping("/v1.0/refsets")
public class RefsetAuthoringController {
private static final Logger logger = LoggerFactory.getLogger(RefsetAuthoringController.class);
private static final String SUCCESS = "Success";
@Resource(name = "browseGraphService")
private RefsetBrowseService bService;
@Resource
private RefsetAuthoringService aService;
@Autowired
private MemberValidator mValidator;
@Autowired
private RefsetValidator rValidator;
@RequestMapping( method = RequestMethod.POST, value = "/new", produces = "application/json", consumes = "application/json")
@ApiOperation( value = "Add a Refset) " )
@PreAuthorize("hasRole('ROLE_USER')")
public ResponseEntity<Result< Map<String, Object>>> addRefset( @RequestBody Refset r) throws Exception {
logger.debug("Adding refsets {}", r);
validateRefset(r);
Set<Member> ms = new HashSet<Member>();
ms.addAll(r.getMembers());
if (ms != null && !ms.isEmpty()) {
validateMembers(ms);
}
Result<Map<String, Object>> result = getResult();
addMetaDetails(r);
r.setCreatedBy(getUserDetails().getUsername());
r.setModifiedBy(getUserDetails().getUsername());
List<Member> members = r.getMembers();
for (Member member : members) {
member.setCreatedBy(getUserDetails().getUsername());
member.setModifiedBy(getUserDetails().getUsername());
}
aService.addRefset(r);
Map<String, Object> data = new HashMap<String, Object>();
data.put("uuid", r.getUuid());
result.getMeta().add( linkTo( methodOn( RefsetBrowseController.class ).getRefsetDetails(r.getUuid())).withRel("Refset"));
result.setData(data);
result.getMeta().setMessage(SUCCESS);
result.getMeta().setStatus(HttpStatus.CREATED);
return new ResponseEntity<Result<Map<String,Object>>>(result, HttpStatus.CREATED);
}
/**Adds meta details in new {@link Refset}
* @param r
* @throws AccessDeniedException
*/
private void addMetaDetails(Refset r) throws AccessDeniedException {
String id = UUID.randomUUID().toString();
r.setUuid(id);
r.setCreated(new DateTime());
r.setCreatedBy(getUserDetails().getUsername());
r.setActive(r.isActive());
}
@RequestMapping( method = RequestMethod.POST, value = "/{refSetId}/add/member", produces = "application/json", consumes = "application/json" )
@ApiOperation( value = "Shortcut method to add a member to an existing refset." )
@PreAuthorize("hasRole('ROLE_USER')")
public ResponseEntity<Result< Map<String, Object>>> addMember(@PathVariable(value = "refSetId") String refsetId,
@RequestBody( required = true) Member member) throws Exception {
logger.debug("Adding member {} to refset {}", member, refsetId);
Set<Member> ms = new HashSet<Member>();
ms.add(member);
if (ms != null && !ms.isEmpty()) {
validateMembers(ms);
}
Result<Map<String, Object>> result = new Result<Map<String, Object>>();
Meta m = new Meta();
member.setCreatedBy(getUserDetails().getUsername());
member.setModifiedBy(getUserDetails().getUsername());
aService.addMember(refsetId, member);
Map<String, Object> data = new HashMap<String, Object>();
data.put("uuid", refsetId);
m.add( linkTo( methodOn( RefsetBrowseController.class ).getRefsetDetails(refsetId)).withRel("Refset"));
result.setData(data);
m.setMessage(SUCCESS);
m.setStatus(HttpStatus.OK);
return new ResponseEntity<Result<Map<String,Object>>>(result, HttpStatus.OK);
}
@RequestMapping( method = RequestMethod.POST, value = "/update", produces = "application/json", consumes = "application/json")
@ApiOperation( value = "Update a Refset" )
@PreAuthorize("hasRole('ROLE_USER')")
public ResponseEntity<Result< Map<String, Object>>> updateRefset( @RequestBody Refset r) throws Exception {
logger.debug("Updating an existing refsets {}", r);
validateRefset(r);
Set<Member> ms = new HashSet<Member>();
ms.addAll(r.getMembers());
if (ms != null && !ms.isEmpty()) {
validateMembers(ms);
}
Result<Map<String, Object>> response = new Result<Map<String, Object>>();
Meta m = new Meta();
response.setMeta(m);
r.setModifiedBy(getUserDetails().getUsername());
List<Member> members = r.getMembers();
for (Member member : members) {
member.setModifiedBy(getUserDetails().getUsername());
}
aService.updateRefset(r);
Map<String, Object> data = new HashMap<String, Object>();
data.put("uuid", r.getUuid());
m.add( linkTo( methodOn( RefsetBrowseController.class ).getRefsetDetails(r.getUuid())).withRel("Refset"));
response.setData(data);
m.setMessage(SUCCESS);
m.setStatus(HttpStatus.OK);
return new ResponseEntity<Result<Map<String,Object>>>(response, HttpStatus.OK);
}
@RequestMapping( method = RequestMethod.DELETE, value = "/delete/{refsetId}", produces = "application/json", consumes = "application/json")
@ApiOperation( value = "Remove a unpublished refset, it will delete refset as well as its members" )
@PreAuthorize("hasRole('ROLE_USER')")
public ResponseEntity<Result< Map<String, Object>>> removeRefset( @PathVariable String refsetId,
@RequestHeader("X-REFSET-PRE-AUTH-TOKEN") String authToken,
@RequestHeader("X-REFSET-PRE-AUTH-USERNAME") String userName) throws Exception {
logger.debug("Removing an existing refsets {}", refsetId);
Result<Map<String, Object>> response = new Result<Map<String, Object>>();
Meta m = new Meta();
response.setMeta(m);
Assert.notNull(refsetId, "Required refset id is not available in request");
aService.remove(refsetId, getUserDetails().getUsername());
m.add( linkTo( methodOn( RefsetBrowseController.class ).getRefsets(1, 10)).withRel("Refset"));
m.setMessage(SUCCESS);
m.setStatus(HttpStatus.OK);
return new ResponseEntity<Result<Map<String,Object>>>(response, HttpStatus.OK);
}
@RequestMapping( method = RequestMethod.POST, value = "/{refSetId}/add/members", produces = "application/json", consumes = "application/json" )
@ApiOperation( value = "Add no of members in this call. It is required that member supplied is a valid member" )
@PreAuthorize("hasRole('ROLE_USER')")
public ResponseEntity<Result< Map<String, Object>>> addMembers(@PathVariable(value = "refSetId") String refsetId,
@RequestBody( required = true) Set<Member> members) throws Exception {
logger.debug("Adding member {} to refset {}", members, refsetId);
validateMembers(members);
Result<Map<String, Object>> result = new Result<Map<String, Object>>();
Meta m = new Meta();
for (Member member : members) {
member.setCreatedBy(getUserDetails().getUsername());
member.setModifiedBy(getUserDetails().getUsername());
member.setCreated(new DateTime());
member.setModifiedDate(new DateTime());
}
Map<String, String> outcome = aService.addMembers(refsetId, members, getUserDetails().getUsername());
Map<String, Object> data = new HashMap<String, Object>();
data.put("outcome", outcome);
m.add( linkTo( methodOn( RefsetBrowseController.class ).getRefsetDetails(refsetId)).withRel("Refset"));
result.setData(data);
m.setMessage(SUCCESS);
m.setStatus(HttpStatus.OK);
return new ResponseEntity<Result<Map<String,Object>>>(result, HttpStatus.OK);
}
/**
* @param members
*/
private void validateMembers(Set<Member> members) throws ValidationException {
// TODO Auto-generated method stub
Map<Object, List<FieldError>> errors = new HashMap<Object, List<FieldError>>();
for (Member m : members) {
Errors e = new BeanPropertyBindingResult(m, "member");
mValidator.validate(m, e );
if (e.hasErrors()) {
errors.put(m, e.getFieldErrors());
}
}
if (!errors.isEmpty()) {
throw new ValidationException(errors);
}
}
@RequestMapping( method = RequestMethod.DELETE, value = "/delete/{refsetId}/member/{referenceComponentId}", produces = "application/json", consumes = "application/json")
@ApiOperation( value = "Removes a member from refset" )
@PreAuthorize("hasRole('ROLE_USER')")
public ResponseEntity<Result< Map<String, Object>>> removeMember( @PathVariable String refsetId,
@PathVariable String referenceComponentId) throws Exception {
logger.debug("Removing an existing refsets {}", refsetId);
Result<Map<String, Object>> response = new Result<Map<String, Object>>();
Meta m = new Meta();
response.setMeta(m);
Assert.notNull(refsetId, "Required refset id is not available in request");
aService.removeMemberFromRefset(refsetId, referenceComponentId, getUserDetails().getUsername());
m.add( linkTo( methodOn( RefsetBrowseController.class ).getRefsets(1, 10)).withRel("Refset"));
m.setMessage(SUCCESS);
m.setStatus(HttpStatus.OK);
return new ResponseEntity<Result<Map<String,Object>>>(response, HttpStatus.OK);
}
@RequestMapping( method = RequestMethod.DELETE, value = "/delete/{refsetId}/members", produces = "application/json", consumes = "application/json")
@ApiOperation( value = "Removes list of members from refset." )
@PreAuthorize("hasRole('ROLE_USER')")
public ResponseEntity<Result< Map<String, Object>>> removeMembers( @PathVariable String refsetId,
@RequestBody Set<String> referencedComponentIds) throws Exception {
logger.debug("Removing an existing refsets {}", refsetId);
Result<Map<String, Object>> result = new Result<Map<String, Object>>();
Meta m = new Meta();
result.setMeta(m);
Map<String, String> outcome = aService.removeMembers(refsetId, referencedComponentIds, getUserDetails().getUsername());
Map<String, Object> data = new HashMap<String, Object>();
data.put("outcome", outcome);
m.add( linkTo( methodOn( RefsetBrowseController.class ).getRefsetDetails(refsetId)).withRel("Refset"));
result.setData(data);
m.setMessage(SUCCESS);
m.setStatus(HttpStatus.OK);
return new ResponseEntity<Result<Map<String,Object>>>(result, HttpStatus.OK);
}
/**
* @param members
*/
private void validateRefset(Refset r) throws ValidationException {
// TODO Auto-generated method stub
Map<Object, List<FieldError>> errors = new HashMap<Object, List<FieldError>>();
Errors e = new BeanPropertyBindingResult(r, "refset");
rValidator.validate(r, e );
if (e.hasErrors()) {
errors.put(r, e.getFieldErrors());
}
if (!errors.isEmpty()) {
throw new ValidationException(errors);
}
}
}