diff --git a/src/main/java/edu/tamu/app/config/AppEmailConfig.java b/src/main/java/edu/tamu/app/config/AppEmailConfig.java new file mode 100644 index 0000000..c80b387 --- /dev/null +++ b/src/main/java/edu/tamu/app/config/AppEmailConfig.java @@ -0,0 +1,12 @@ +package edu.tamu.app.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import edu.tamu.weaver.email.config.WeaverEmailConfig; + +@Configuration +@Profile("!test") +public class AppEmailConfig extends WeaverEmailConfig { + +} \ No newline at end of file diff --git a/src/main/java/edu/tamu/app/controller/IdeaController.java b/src/main/java/edu/tamu/app/controller/IdeaController.java index c695bad..e93ad1a 100644 --- a/src/main/java/edu/tamu/app/controller/IdeaController.java +++ b/src/main/java/edu/tamu/app/controller/IdeaController.java @@ -1,6 +1,7 @@ package edu.tamu.app.controller; import static edu.tamu.weaver.response.ApiStatus.SUCCESS; +import static edu.tamu.weaver.response.ApiStatus.INVALID; import static edu.tamu.weaver.validation.model.BusinessValidationType.CREATE; import org.springframework.beans.factory.annotation.Autowired; @@ -52,6 +53,18 @@ public ApiResponse create(@WeaverValidatedModel Idea idea, @WeaverCredentials Cr public ApiResponse update(@WeaverValidatedModel Idea idea) { return new ApiResponse(SUCCESS, ideaRepo.update(idea)); } + + @RequestMapping("/reject") + @PreAuthorize("hasRole('SERVICE_MANAGER')") + public ApiResponse reject(@WeaverValidatedModel Idea idea) { + ApiResponse response; + if (idea.getFeedback() == null || idea.getFeedback().equals("")) { + response = new ApiResponse(INVALID, "You must provide feedback to reject an idea."); + } else { + response = new ApiResponse(SUCCESS, ideaRepo.reject(idea)); + } + return response; + } @Transactional @RequestMapping("/remove") diff --git a/src/main/java/edu/tamu/app/model/Idea.java b/src/main/java/edu/tamu/app/model/Idea.java index 1f4b18d..6beef58 100644 --- a/src/main/java/edu/tamu/app/model/Idea.java +++ b/src/main/java/edu/tamu/app/model/Idea.java @@ -26,6 +26,12 @@ public class Idea extends AbstractIdea { @Enumerated(EnumType.STRING) @Column(nullable = false) private IdeaState state; + + @Column(nullable = true) + private String feedback; + + @Column(nullable = true) + private String email; @ManyToOne(fetch = EAGER, cascade = { CascadeType.REFRESH, CascadeType.DETACH }, optional = true) @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, scope = FeatureProposal.class, property = "id") @@ -43,8 +49,13 @@ public Idea(String title, String description) { this.state = IdeaState.WAITING_ON_REVIEW; } + public Idea(String title, String description, String email) { + this(title, description); + setEmail(email); + } + public Idea(ServiceRequest serviceRequest) { - this(serviceRequest.getTitle(), serviceRequest.getDescription()); + this(serviceRequest.getTitle(), serviceRequest.getDescription(), serviceRequest.getEmail()); } public Idea(String title, String description, User author) { @@ -56,6 +67,11 @@ public Idea(String title, String description, User author, Service service) { super(title, description, author, service); this.state = IdeaState.WAITING_ON_REVIEW; } + + public Idea(String title, String description, User author, Service service, String email) { + this(title, description, author, service); + this.email = email; + } public IdeaState getState() { return state; @@ -65,6 +81,22 @@ public void setState(IdeaState state) { this.state = state; } + public String getFeedback() { + return feedback; + } + + public void setFeedback(String feedback) { + this.feedback = feedback; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + public FeatureProposal getFeatureProposal() { return featureProposal; } diff --git a/src/main/java/edu/tamu/app/model/repo/custom/IdeaRepoCustom.java b/src/main/java/edu/tamu/app/model/repo/custom/IdeaRepoCustom.java index 45de971..62a65e7 100644 --- a/src/main/java/edu/tamu/app/model/repo/custom/IdeaRepoCustom.java +++ b/src/main/java/edu/tamu/app/model/repo/custom/IdeaRepoCustom.java @@ -12,4 +12,6 @@ public interface IdeaRepoCustom { public void delete(Idea idea); + public Idea reject(Idea idea); + } diff --git a/src/main/java/edu/tamu/app/model/repo/impl/IdeaRepoImpl.java b/src/main/java/edu/tamu/app/model/repo/impl/IdeaRepoImpl.java index 8ba6ef2..1005968 100644 --- a/src/main/java/edu/tamu/app/model/repo/impl/IdeaRepoImpl.java +++ b/src/main/java/edu/tamu/app/model/repo/impl/IdeaRepoImpl.java @@ -4,9 +4,12 @@ import java.util.Optional; +import javax.mail.MessagingException; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.simp.SimpMessagingTemplate; +import edu.tamu.app.enums.IdeaState; import edu.tamu.app.exception.UserNotFoundException; import edu.tamu.app.model.Idea; import edu.tamu.app.model.User; @@ -14,16 +17,22 @@ import edu.tamu.app.model.repo.UserRepo; import edu.tamu.app.model.repo.custom.IdeaRepoCustom; import edu.tamu.weaver.auth.model.Credentials; +import edu.tamu.weaver.email.service.EmailSender; import edu.tamu.weaver.response.ApiResponse; public class IdeaRepoImpl implements IdeaRepoCustom { + private static final String REJECTION_SUBJECT = "Your idea has been rejected."; + @Autowired private UserRepo userRepo; @Autowired private IdeaRepo ideaRepo; + @Autowired + private EmailSender emailService; + @Autowired private SimpMessagingTemplate simpMessagingTemplate; @@ -52,4 +61,17 @@ public void delete(Idea idea) { simpMessagingTemplate.convertAndSend("/channel/ideas/delete", new ApiResponse(SUCCESS, idea.getId())); } + public Idea reject(Idea idea) { + idea.setState(IdeaState.REJECTED); + String body = "Your idea " + idea.getTitle() + ", for " + idea.getService().getName() + ", has been rejected for the following reason:\n" + idea.getFeedback(); + try { + if (idea.getEmail() != null && !idea.getEmail().isEmpty()) { + emailService.sendEmail(idea.getEmail(), REJECTION_SUBJECT, body); + } + + } catch (MessagingException e) { + e.printStackTrace(); + } + return ideaRepo.update(idea); + } } diff --git a/src/main/java/edu/tamu/app/model/request/ServiceRequest.java b/src/main/java/edu/tamu/app/model/request/ServiceRequest.java index a75c4f8..b9c91fb 100644 --- a/src/main/java/edu/tamu/app/model/request/ServiceRequest.java +++ b/src/main/java/edu/tamu/app/model/request/ServiceRequest.java @@ -6,13 +6,20 @@ public class ServiceRequest extends AbstractRequest { private Long service; + private String email; + public ServiceRequest() { super(); } public ServiceRequest(RequestType type, String title, String description, Long service) { super(type, title, description); - this.service = service; + setService(service); + } + + public ServiceRequest(RequestType type, String title, String description, Long service, String email) { + this(type, title, description, service); + setEmail(email); } public Long getService() { @@ -23,4 +30,12 @@ public void setService(Long service) { this.service = service; } + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + } diff --git a/src/test/java/edu/tamu/app/controller/IdeaControllerTest.java b/src/test/java/edu/tamu/app/controller/IdeaControllerTest.java index 310f973..b0cb0c3 100644 --- a/src/test/java/edu/tamu/app/controller/IdeaControllerTest.java +++ b/src/test/java/edu/tamu/app/controller/IdeaControllerTest.java @@ -1,5 +1,6 @@ package edu.tamu.app.controller; +import static edu.tamu.weaver.response.ApiStatus.INVALID; import static edu.tamu.weaver.response.ApiStatus.SUCCESS; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; @@ -23,6 +24,7 @@ import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.test.context.junit4.SpringRunner; +import edu.tamu.app.enums.IdeaState; import edu.tamu.app.enums.Status; import edu.tamu.app.exception.UserNotFoundException; import edu.tamu.app.model.Idea; @@ -51,12 +53,15 @@ public class IdeaControllerTest { private static final String TEST_MODIFIED_IDEA_TITLE = "Modified Idea Title"; private static final String TEST_MODIFIED_IDEA_DESCRIPTION = "Modified Idea Description"; private static final String TEST_SERVICE_NAME = "Test Service"; + private static final String TEST_FEEDBACK = "Test Rejection Feedback"; private static Service TEST_SERVICE = new Service(TEST_SERVICE_NAME, Status.UP, false, true, true, "", ""); private static Idea TEST_IDEA1 = new Idea(TEST_IDEA_TITLE1, TEST_IDEA_DESCRIPTION1, TEST_USER1); private static Idea TEST_IDEA2 = new Idea(TEST_IDEA_TITLE2, TEST_IDEA_DESCRIPTION2, TEST_USER1); private static Idea TEST_IDEA3 = new Idea(TEST_IDEA_TITLE3, TEST_IDEA_DESCRIPTION3, TEST_USER1); private static Idea TEST_MODIFIED_IDEA = new Idea(TEST_MODIFIED_IDEA_TITLE, TEST_MODIFIED_IDEA_DESCRIPTION, TEST_USER2, TEST_SERVICE); + private static Idea ideaWtihFeedback = new Idea(TEST_IDEA_TITLE1, TEST_IDEA_DESCRIPTION1, TEST_USER1); + private Idea rejectedIdea = new Idea(TEST_IDEA_TITLE1, TEST_IDEA_DESCRIPTION1, TEST_USER1); private static List mockIdeaList = new ArrayList(Arrays.asList(new Idea[] { TEST_IDEA1, TEST_IDEA2, TEST_IDEA3 })); private static Page mockPageableIdeaList = new PageImpl(Arrays.asList(new Idea[] { TEST_IDEA1, TEST_IDEA2, TEST_IDEA3 })); @@ -85,6 +90,8 @@ public class IdeaControllerTest { @Before @SuppressWarnings("unchecked") public void setup() throws UserNotFoundException { + rejectedIdea.setState(IdeaState.REJECTED); + ideaWtihFeedback.setFeedback(TEST_FEEDBACK); MockitoAnnotations.initMocks(this); when(credentials.getUin()).thenReturn("123456789"); when(userRepo.findByUsername(any(String.class))).thenReturn(Optional.of(user)); @@ -93,6 +100,7 @@ public void setup() throws UserNotFoundException { when(ideaRepo.findOne(any(Long.class))).thenReturn(TEST_IDEA1); when(ideaRepo.create(any(Idea.class), any(Credentials.class))).thenReturn(TEST_IDEA1); when(ideaRepo.update(any(Idea.class))).thenReturn(TEST_MODIFIED_IDEA); + when(ideaRepo.reject(TEST_IDEA1)).thenReturn(rejectedIdea); when(serviceRepo.findOne(any(Long.class))).thenReturn(TEST_SERVICE); doNothing().when(ideaRepo).delete(any(Idea.class)); doNothing().when(ideaRepo).delete(any(Idea.class)); @@ -132,6 +140,20 @@ public void testUpdate() { assertEquals("Notification Author was not properly updated", TEST_MODIFIED_IDEA.getAuthor(), idea.getAuthor()); } + @Test + public void testReject() { + response = ideaController.reject(ideaWtihFeedback); + assertEquals("Not successful at rejecting idea", SUCCESS, response.getMeta().getStatus()); + Idea idea = (Idea) response.getPayload().get("Idea"); + assertEquals("State was not set to Rejected", rejectedIdea.getState(), idea.getState()); + } + + @Test + public void testInvalidReject() { + response = ideaController.reject(TEST_IDEA1); + assertEquals("Idea without feedback was successfull", INVALID, response.getMeta().getStatus()); + } + @Test public void testRemove() { response = ideaController.remove(TEST_MODIFIED_IDEA); diff --git a/src/test/java/edu/tamu/app/model/IdeaTest.java b/src/test/java/edu/tamu/app/model/IdeaTest.java index 9ba05ea..5c84400 100644 --- a/src/test/java/edu/tamu/app/model/IdeaTest.java +++ b/src/test/java/edu/tamu/app/model/IdeaTest.java @@ -14,6 +14,7 @@ import org.springframework.test.context.junit4.SpringRunner; import edu.tamu.app.StatusApplication; +import edu.tamu.app.enums.IdeaState; import edu.tamu.app.enums.Role; import edu.tamu.app.enums.Status; import edu.tamu.app.exception.UserNotFoundException; @@ -35,6 +36,7 @@ public class IdeaTest { private static final String TEST_ALTERNATIVE_SERVICE_NAME = "Different Service Name"; private static final String TEST_IDEA_DESCRIPTION = "Test Idea Description"; private static final String TEST_ALTERNATIVE_IDEA_DESCRIPTION = "Alternative Idea Description"; + private static final String TEST_IDEA_EMAIL = "aggiejack@mailinator.com"; private static final Boolean TEST_IS_AUTO = false; private static final Boolean TEST_IS_PUBLIC = true; private static final Boolean TEST_ON_SHORT_LIST = true; @@ -78,7 +80,7 @@ public void setUp() throws UserNotFoundException { testUser = userRepo.create(TEST_CREDENTIALS.getUin(), TEST_CREDENTIALS.getEmail(), TEST_CREDENTIALS.getFirstName(), TEST_CREDENTIALS.getLastName(), Role.valueOf(TEST_CREDENTIALS.getRole())); service1 = serviceRepo.create(new Service(TEST_SERVICE_NAME, TEST_SERVICE_STATUS, TEST_IS_AUTO, TEST_IS_PUBLIC, TEST_ON_SHORT_LIST, TEST_SERVICE_URL, TEST_DESCRIPTION)); service2 = serviceRepo.create(new Service(TEST_ALTERNATIVE_SERVICE_NAME, TEST_SERVICE_STATUS, TEST_IS_AUTO, TEST_IS_PUBLIC, TEST_ON_SHORT_LIST, TEST_SERVICE_URL, TEST_DESCRIPTION)); - testIdea = ideaRepo.create(new Idea(TEST_IDEA_TITLE, TEST_IDEA_DESCRIPTION, testUser, service1), TEST_CREDENTIALS); + testIdea = ideaRepo.create(new Idea(TEST_IDEA_TITLE, TEST_IDEA_DESCRIPTION, testUser, service1, TEST_IDEA_EMAIL), TEST_CREDENTIALS); testFeatureProposal = featureProposalRepo.create(new FeatureProposal(TEST_FEATURE_PROPOSAL_TITLE, TEST_FEATURE_PROPOSAL_DESCRIPTION, testUser, service1), TEST_CREDENTIALS); } @@ -144,6 +146,20 @@ public void testUpdateFeatureProposal() throws UserNotFoundException { assertEquals("Feature proposal does not have idea", idea, testFeatureProposal.getIdeas().get(0)); } + @Test + public void testReject() throws UserNotFoundException { + Idea idea = ideaRepo.create(testIdea, TEST_CREDENTIALS); + idea = ideaRepo.reject(idea); + + assertEquals("Idea was not rejected", IdeaState.REJECTED, idea.getState()); + } + + @Test + public void testRejectException() { + Idea idea = new Idea(TEST_IDEA_TITLE, TEST_IDEA_DESCRIPTION, testUser, service1); + ideaRepo.reject(idea); + } + @Test public void testTimestampSetOnCreate() throws UserNotFoundException { Idea Idea = ideaRepo.create(testIdea, TEST_CREDENTIALS); diff --git a/src/test/java/edu/tamu/app/model/impl/ShibTest.java b/src/test/java/edu/tamu/app/model/ShibTest.java similarity index 98% rename from src/test/java/edu/tamu/app/model/impl/ShibTest.java rename to src/test/java/edu/tamu/app/model/ShibTest.java index 52b0e83..d9349e2 100644 --- a/src/test/java/edu/tamu/app/model/impl/ShibTest.java +++ b/src/test/java/edu/tamu/app/model/ShibTest.java @@ -1,4 +1,4 @@ -package edu.tamu.app.model.impl; +package edu.tamu.app.model; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/edu/tamu/app/model/request/ServiceRequestTest.java b/src/test/java/edu/tamu/app/model/request/ServiceRequestTest.java new file mode 100644 index 0000000..9ba973f --- /dev/null +++ b/src/test/java/edu/tamu/app/model/request/ServiceRequestTest.java @@ -0,0 +1,37 @@ +package edu.tamu.app.model.request; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.junit4.SpringRunner; + +import edu.tamu.app.model.request.AbstractRequest.RequestType; + +@RunWith(SpringRunner.class) +public class ServiceRequestTest { + + private static final RequestType TEST_REQUEST_TYPE = RequestType.FEATURE; + private static final String TEST_TITLE = "Test Request title"; + private static final String TEST_DESCRIPTION = "Test Request Description"; + private static final Long TEST_SERVICE_ID = 1L; + private static final String TEST_EMAIL = "aggiejack@mailinator.com"; + + @Test + public void testConstructors() { + // Constructor without email + ServiceRequest serviceRequest = new ServiceRequest(TEST_REQUEST_TYPE, TEST_TITLE, TEST_DESCRIPTION, TEST_SERVICE_ID); + assertEquals("Type was not set", RequestType.FEATURE, serviceRequest.getType()); + assertEquals("Title was not set", TEST_TITLE, serviceRequest.getTitle()); + assertEquals("Description was not set", TEST_DESCRIPTION, serviceRequest.getDescription()); + assertEquals("Service ID was not set", TEST_SERVICE_ID, serviceRequest.getService()); + + // Constructor with email + ServiceRequest serviceRequestWithEmail = new ServiceRequest(TEST_REQUEST_TYPE, TEST_TITLE, TEST_DESCRIPTION, TEST_SERVICE_ID, TEST_EMAIL); + assertEquals("Type was not set", RequestType.FEATURE, serviceRequestWithEmail.getType()); + assertEquals("Title was not set", TEST_TITLE, serviceRequestWithEmail.getTitle()); + assertEquals("Description was not set", TEST_DESCRIPTION, serviceRequestWithEmail.getDescription()); + assertEquals("Service ID was not set", TEST_SERVICE_ID, serviceRequestWithEmail.getService()); + assertEquals("Email was not set", TEST_EMAIL, serviceRequestWithEmail.getEmail()); + } +}