package svanimpe.reminders.resources; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.Set; import javax.annotation.Resource; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.json.Json; import javax.json.JsonException; import javax.json.JsonObject; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; import javax.transaction.Transactional; import javax.validation.ConstraintViolation; import javax.validation.Validator; import javax.ws.rs.BadRequestException; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.ForbiddenException; import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; 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.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import svanimpe.reminders.domain.List; import svanimpe.reminders.domain.Reminder; import svanimpe.reminders.domain.Role; import svanimpe.reminders.domain.User; import static svanimpe.reminders.util.Utilities.mergeMessages; @Path("lists") @Transactional(dontRollbackOn = {BadRequestException.class, ForbiddenException.class, NotFoundException.class}) @RequestScoped public class Lists { @PersistenceContext private EntityManager em; @Resource private Validator validator; @Context private SecurityContext context; @GET @Produces(MediaType.APPLICATION_JSON) public java.util.List<List> getLists() { TypedQuery<List> q = em.createNamedQuery("List.findByOwner", List.class); q.setParameter("owner", em.find(User.class, context.getUserPrincipal().getName())); return q.getResultList(); } @POST @Consumes(MediaType.APPLICATION_JSON) public Response addList(List list) { // If the list doesn't have an owner, set it to the current user. if (list.getOwner() == null) { list.setOwner(em.find(User.class, context.getUserPrincipal().getName())); } // Only admins can create lists for other users. if (!list.getOwner().getUsername().equals(context.getUserPrincipal().getName()) && !context.isUserInRole(Role.ADMINISTRATOR.name())) { throw new ForbiddenException(); } Set<ConstraintViolation<List>> violations = validator.validate(list); if (!violations.isEmpty()) { throw new BadRequestException(mergeMessages(violations)); } em.persist(list); return Response.created(URI.create("/lists/" + list.getId())).build(); } @GET @Path("{listid}") @Produces(MediaType.APPLICATION_JSON) public List getList(@PathParam("listid") long id) { List list = em.find(List.class, id); if (list == null) { throw new NotFoundException(); } // Only admins can read other user's lists. if (!list.getOwner().getUsername().equals(context.getUserPrincipal().getName()) && !context.isUserInRole(Role.ADMINISTRATOR.name())) { throw new ForbiddenException(); } return list; } @PUT @Path("{listid}") @Consumes(MediaType.APPLICATION_JSON) public void updateList(@PathParam("listid") long id, InputStream in) { List list = em.find(List.class, id); if (list == null) { throw new NotFoundException(); } // Only admins can update other user's lists. if (!list.getOwner().getUsername().equals(context.getUserPrincipal().getName()) && !context.isUserInRole(Role.ADMINISTRATOR.name())) { throw new ForbiddenException(); } em.detach(list); try { JsonObject update = Json.createReader(in).readObject(); if (update.containsKey("title")) { list.setTitle(update.getString("title")); } if (update.containsKey("owner")) { User newOwner = em.find(User.class, update.getString("owner")); if (newOwner == null) { throw new NotFoundException(); } // Only admins can change the owner of a list. if (!newOwner.equals(list.getOwner()) && !context.isUserInRole(Role.ADMINISTRATOR.name())) { throw new ForbiddenException(); } else { list.setOwner(newOwner); } } } catch (JsonException | ClassCastException ex) { // Invalid JSON or type mismatch. throw new BadRequestException("JSON"); } Set<ConstraintViolation<List>> violations = validator.validate(list); if (!violations.isEmpty()) { throw new BadRequestException(mergeMessages(violations)); } em.merge(list); } @Inject private Reminders remindersResource; @DELETE @Path("{listid}") public void removeList(@PathParam("listid") long id) throws IOException { List list = em.find(List.class, id); if (list == null) { throw new NotFoundException(); } // Only admins can delete other user's lists. if (!list.getOwner().getUsername().equals(context.getUserPrincipal().getName()) && !context.isUserInRole(Role.ADMINISTRATOR.name())) { throw new ForbiddenException(); } TypedQuery<Reminder> q = em.createNamedQuery("Reminder.findByList", Reminder.class).setParameter("list", list); for (Reminder reminder : q.getResultList()) { remindersResource.removeReminder(list.getId(), reminder.getId()); } em.remove(list); } }