package fi.otavanopisto.muikku.plugins.user.rest;
import java.io.IOException;
import javax.ejb.Stateful;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.EntityTag;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import fi.otavanopisto.muikku.files.TempFileUtils;
import fi.otavanopisto.muikku.model.users.EnvironmentRoleArchetype;
import fi.otavanopisto.muikku.model.users.EnvironmentUser;
import fi.otavanopisto.muikku.model.users.UserEntity;
import fi.otavanopisto.muikku.model.users.UserEntityFile;
import fi.otavanopisto.muikku.model.users.UserEntityFileVisibility;
import fi.otavanopisto.muikku.plugin.PluginRESTService;
import fi.otavanopisto.muikku.plugins.user.UserEntityFileController;
import fi.otavanopisto.muikku.session.SessionController;
import fi.otavanopisto.muikku.users.EnvironmentUserController;
import fi.otavanopisto.muikku.users.UserEntityController;
import fi.otavanopisto.security.rest.RESTPermit;
import fi.otavanopisto.security.rest.RESTPermit.Handling;
@RequestScoped
@Path("/user/files")
@Stateful
@Produces("application/json")
public class UserEntityFileRESTService extends PluginRESTService {
private static final long serialVersionUID = 8589224539219569240L;
@Inject
private EnvironmentUserController environmentUserController;
@Inject
private UserEntityController userEntityController;
@Inject
private UserEntityFileController userEntityFileController;
@Inject
private SessionController sessionController;
@POST
@Path("/")
@RESTPermit (handling = Handling.INLINE, requireLoggedIn = true)
public Response createUserEntityFile(RestUserEntityFile entity) {
// Entity validation
if (StringUtils.isBlank(entity.getContentType())) {
return Response.status(Status.BAD_REQUEST).entity("contentType is missing").build();
}
if (StringUtils.isBlank(entity.getFileId()) && StringUtils.isBlank(entity.getBase64Data())) {
return Response.status(Status.BAD_REQUEST).entity("fileId or base64Data is missing").build();
}
if (StringUtils.isBlank(entity.getIdentifier())) {
return Response.status(Status.BAD_REQUEST).entity("identifier is missing").build();
}
if (StringUtils.isBlank(entity.getName())) {
return Response.status(Status.BAD_REQUEST).entity("name is missing").build();
}
if (entity.getVisibility() == null) {
return Response.status(Status.BAD_REQUEST).entity("visibility is missing").build();
}
// File data (fileId)
byte[] content = null;
if (StringUtils.isNotBlank(entity.getFileId())) {
try {
content = TempFileUtils.getTempFileData(entity.getFileId());
}
catch (IOException e) {
return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
}
else if (StringUtils.isNotBlank(entity.getBase64Data())) {
String base64Image = entity.getBase64Data().split(",")[1];
content = DatatypeConverter.parseBase64Binary(base64Image);
}
if (content == null) {
return Response.status(Status.BAD_REQUEST).entity("fileId is invalid").build();
}
// Store file
UserEntityFile userEntityFile = userEntityFileController.storeUserEntityFile(entity.getIdentifier(), entity.getName(), entity.getContentType(), content, entity.getVisibility());
if (userEntityFile == null) {
return Response.status(Status.NOT_FOUND).build();
}
else {
return Response.ok(createRestModel(userEntityFile)).build();
}
}
@GET
@Path("/user/{USERENTITYID}/identifier/{IDENTIFIER}")
@RESTPermit (handling = Handling.INLINE)
public Response getFileContent(@PathParam("USERENTITYID") Long userEntityId, @PathParam("IDENTIFIER") String identifier, @Context Request request) {
// Check if the file exists
UserEntity userEntity = userEntityController.findUserEntityById(userEntityId);
if (userEntity == null) {
return Response.status(Status.NOT_FOUND).build();
}
UserEntityFile userEntityFile = userEntityFileController.findByUserEntityAndIdentifier(userEntity, identifier);
if (userEntityFile == null) {
return Response.status(Status.NOT_FOUND).build();
}
// Check if the caller has access to the file
if (userEntityFile.getVisibility() != UserEntityFileVisibility.PUBLIC) {
UserEntity loggedUserEntity = sessionController.getLoggedUserEntity();
if (loggedUserEntity == null) {
return Response.status(Status.NOT_FOUND).build();
}
else if (!userEntityFile.getUserEntity().getId().equals(loggedUserEntity.getId())) {
if (userEntityFile.getVisibility() == UserEntityFileVisibility.STAFF) {
EnvironmentUser environmentUser = environmentUserController.findEnvironmentUserByUserEntity(loggedUserEntity);
if (environmentUser == null || environmentUser.getRole() == null || environmentUser.getRole().getArchetype() == EnvironmentRoleArchetype.STUDENT) {
return Response.status(Status.NOT_FOUND).build();
}
}
else {
return Response.status(Status.NOT_FOUND).build();
}
}
}
// Serve the content
String tagIdentifier = String.format("%d-%s-%d", userEntityFile.getUserEntity().getId(), userEntityFile.getIdentifier(), userEntityFile.getLastModified().getTime());
EntityTag tag = new EntityTag(DigestUtils.md5Hex(String.valueOf(tagIdentifier)));
ResponseBuilder builder = request.evaluatePreconditions(tag);
if (builder != null) {
return builder.build();
}
CacheControl cacheControl = new CacheControl();
cacheControl.setMustRevalidate(true);
byte[] data = userEntityFile.getData();
return Response.ok(data)
.cacheControl(cacheControl)
.tag(tag)
.header("Content-Length", data.length)
.header("Content-Disposition", String.format("attachment; filename=\"%s\"", userEntityFile.getName()))
.type(userEntityFile.getContentType())
.build();
}
private RestUserEntityFile createRestModel(UserEntityFile userEntityFile) {
RestUserEntityFile restUserEntityFile = new RestUserEntityFile();
restUserEntityFile.setContentType(userEntityFile.getContentType());
restUserEntityFile.setId(userEntityFile.getId());
restUserEntityFile.setIdentifier(userEntityFile.getIdentifier());
restUserEntityFile.setName(userEntityFile.getName());
restUserEntityFile.setUserEntityId(userEntityFile.getUserEntity().getId());
restUserEntityFile.setVisibility(userEntityFile.getVisibility());
return restUserEntityFile;
}
}