diff --git a/pom.xml b/pom.xml index 0889d8a6..3a256afb 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ ubc.pavlab rdp - 1.4.4 + 1.4.5 @@ -210,6 +210,7 @@ feature- hotfix- support- + v diff --git a/src/main/java/ubc/pavlab/rdp/controllers/LoginController.java b/src/main/java/ubc/pavlab/rdp/controllers/LoginController.java index a2823d8d..e653da78 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/LoginController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/LoginController.java @@ -2,7 +2,6 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.core.Authentication; @@ -16,11 +15,9 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; -import ubc.pavlab.rdp.events.OnRegistrationCompleteEvent; import ubc.pavlab.rdp.exception.TokenException; import ubc.pavlab.rdp.model.Profile; import ubc.pavlab.rdp.model.User; -import ubc.pavlab.rdp.model.VerificationToken; import ubc.pavlab.rdp.services.PrivacyService; import ubc.pavlab.rdp.services.UserService; import ubc.pavlab.rdp.settings.ApplicationSettings; @@ -43,9 +40,6 @@ public class LoginController { @Autowired private ApplicationSettings applicationSettings; - @Autowired - private ApplicationEventPublisher eventPublisher; - @GetMapping("/login") public ModelAndView login() { ModelAndView modelAndView = new ModelAndView( "login" ); @@ -67,7 +61,6 @@ public ModelAndView registration() { return modelAndView; } - @Transactional @PostMapping("/registration") public ModelAndView createNewUser( @Validated(User.ValidationUserAccount.class) User user, BindingResult bindingResult, @@ -94,8 +87,7 @@ public ModelAndView createNewUser( @Validated(User.ValidationUserAccount.class) modelAndView.setStatus( HttpStatus.BAD_REQUEST ); } else { user = userService.create( user ); - VerificationToken token = userService.createVerificationTokenForUser( user ); - eventPublisher.publishEvent( new OnRegistrationCompleteEvent( user, token, locale ) ); + userService.createVerificationTokenForUser( user, locale ); redirectAttributes.addFlashAttribute( "message", "Your user account was registered successfully. Please check your email for completing the completing the registration process." ); modelAndView.setViewName( "redirect:/login" ); } @@ -108,7 +100,6 @@ public ModelAndView resendConfirmation() { return new ModelAndView( "resendConfirmation" ); } - @Transactional @PostMapping(value = "/resendConfirmation") public ModelAndView resendConfirmation( @RequestParam("email") String email, Locale locale ) { ModelAndView modelAndView = new ModelAndView( "resendConfirmation" ); @@ -125,8 +116,7 @@ public ModelAndView resendConfirmation( @RequestParam("email") String email, Loc modelAndView.addObject( "message", "User is already enabled." ); return modelAndView; } else { - VerificationToken token = userService.createVerificationTokenForUser( user ); - eventPublisher.publishEvent( new OnRegistrationCompleteEvent( user, token, locale ) ); + userService.createVerificationTokenForUser( user, locale ); modelAndView.addObject( "message", "Confirmation email sent." ); } diff --git a/src/main/java/ubc/pavlab/rdp/controllers/PasswordController.java b/src/main/java/ubc/pavlab/rdp/controllers/PasswordController.java index 77c727fd..e7c6cd21 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/PasswordController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/PasswordController.java @@ -1,17 +1,21 @@ package ubc.pavlab.rdp.controllers; +import ch.qos.logback.core.joran.spi.EventPlayer; import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; +import ubc.pavlab.rdp.events.OnUserPasswordResetEvent; import ubc.pavlab.rdp.exception.TokenException; import ubc.pavlab.rdp.model.PasswordReset; import ubc.pavlab.rdp.model.PasswordResetToken; @@ -35,9 +39,6 @@ public class PasswordController { @Autowired private UserService userService; - @Autowired - private EmailService emailService; - @GetMapping(value = "/forgotPassword") public ModelAndView forgotPassword() { return new ModelAndView( "forgotPassword" ); @@ -57,16 +58,7 @@ public ModelAndView resetPassword( @RequestParam("email") String userEmail, Loca return modelAndView; } - PasswordResetToken token = userService.createPasswordResetTokenForUser( user ); - try { - emailService.sendResetTokenMessage( user, token, locale ); - } catch ( MessagingException e ) { - modelAndView.setStatus( HttpStatus.INTERNAL_SERVER_ERROR ); - modelAndView.addObject( "message", "We had trouble sending an email to your address." ); - modelAndView.addObject( "error", Boolean.TRUE ); - log.error( MessageFormat.format( "Failed to send reset token message to {0}.", user ), e ); - return modelAndView; - } + userService.createPasswordResetTokenForUser( user, locale ); modelAndView.addObject( "message", "Password reset instructions have been sent." ); modelAndView.addObject( "error", Boolean.FALSE ); diff --git a/src/main/java/ubc/pavlab/rdp/controllers/SearchController.java b/src/main/java/ubc/pavlab/rdp/controllers/SearchController.java index 8b0f6bb7..940759fa 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/SearchController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/SearchController.java @@ -4,7 +4,6 @@ import lombok.extern.apachecommons.CommonsLog; import org.hibernate.validator.constraints.NotBlank; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.MessageSource; import org.springframework.http.HttpStatus; import org.springframework.security.access.PermissionEvaluator; @@ -13,7 +12,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; -import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -23,7 +21,6 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import org.springframework.web.servlet.view.RedirectView; -import ubc.pavlab.rdp.events.OnRequestAccessEvent; import ubc.pavlab.rdp.exception.RemoteException; import ubc.pavlab.rdp.model.*; import ubc.pavlab.rdp.model.enums.ResearcherCategory; @@ -68,9 +65,6 @@ public class SearchController { @Autowired private PermissionEvaluator permissionEvaluator; - @Autowired - private ApplicationEventPublisher eventPublisher; - @PreAuthorize("hasPermission(null, 'search')") @GetMapping(value = "/search") public ModelAndView search() { @@ -550,7 +544,6 @@ public Object requestGeneAccessView( @PathVariable UUID anonymousId, return modelAndView; } - @Transactional @Secured({ "ROLE_USER", "ROLE_ADMIN" }) @PostMapping("/search/gene/by-anonymous-id/{anonymousId}/request-access") public ModelAndView requestGeneAccess( @PathVariable UUID anonymousId, @@ -570,7 +563,7 @@ public ModelAndView requestGeneAccess( @PathVariable UUID anonymousId, if ( bindingResult.hasErrors() ) { modelAndView.setStatus( HttpStatus.BAD_REQUEST ); } else { - eventPublisher.publishEvent( new OnRequestAccessEvent( userService.findCurrentUser(), userGene, requestAccessForm.reason ) ); + userService.sendGeneAccessRequest( userService.findCurrentUser(), userGene, requestAccessForm.getReason() ); redirectAttributes.addFlashAttribute( "message", "An access request has been sent and will be reviewed." ); return new ModelAndView( "redirect:/search" ); } diff --git a/src/main/java/ubc/pavlab/rdp/controllers/UserController.java b/src/main/java/ubc/pavlab/rdp/controllers/UserController.java index d47dfe2b..348d0205 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/UserController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/UserController.java @@ -12,13 +12,11 @@ import org.springframework.security.access.annotation.Secured; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.stereotype.Controller; -import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; -import ubc.pavlab.rdp.events.OnContactEmailUpdateEvent; import ubc.pavlab.rdp.exception.TokenException; import ubc.pavlab.rdp.model.*; import ubc.pavlab.rdp.model.enums.PrivacyLevelType; @@ -56,9 +54,6 @@ public class UserController { @Autowired private EmailService emailService; - @Autowired - private ApplicationEventPublisher eventPublisher; - @Autowired private ApplicationSettings applicationSettings; @@ -221,15 +216,13 @@ public ModelAndView changePassword( @Valid PasswordChange passwordChange, Bindin return modelAndView; } - @Transactional @PostMapping("/user/resend-contact-email-verification") public Object resendContactEmailVerification( RedirectAttributes redirectAttributes, Locale locale ) { User user = userService.findCurrentUser(); if ( user.getProfile().isContactEmailVerified() ) { return ResponseEntity.badRequest().body( "Contact email is already verified." ); } - VerificationToken token = userService.createContactEmailVerificationTokenForUser( user ); - eventPublisher.publishEvent( new OnContactEmailUpdateEvent( user, token, locale ) ); + userService.createContactEmailVerificationTokenForUser( user, locale ); redirectAttributes.addFlashAttribute( "message", MessageFormat.format( "We will send an email to {0} with a link to verify your contact email.", user.getProfile().getContactEmail() ) ); return "redirect:/user/profile"; } diff --git a/src/main/java/ubc/pavlab/rdp/events/OnContactEmailUpdateEvent.java b/src/main/java/ubc/pavlab/rdp/events/OnContactEmailUpdateEvent.java index 0fc7f64c..c6139f9c 100644 --- a/src/main/java/ubc/pavlab/rdp/events/OnContactEmailUpdateEvent.java +++ b/src/main/java/ubc/pavlab/rdp/events/OnContactEmailUpdateEvent.java @@ -9,7 +9,7 @@ import java.util.Locale; @Getter -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode public class OnContactEmailUpdateEvent extends ApplicationEvent { private final User user; diff --git a/src/main/java/ubc/pavlab/rdp/events/OnRegistrationCompleteEvent.java b/src/main/java/ubc/pavlab/rdp/events/OnRegistrationCompleteEvent.java index 84af20b8..33f3d972 100644 --- a/src/main/java/ubc/pavlab/rdp/events/OnRegistrationCompleteEvent.java +++ b/src/main/java/ubc/pavlab/rdp/events/OnRegistrationCompleteEvent.java @@ -13,7 +13,7 @@ * Created by mjacobson on 22/01/18. */ @Getter -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode public class OnRegistrationCompleteEvent extends ApplicationEvent { private final User user; diff --git a/src/main/java/ubc/pavlab/rdp/events/OnRequestAccessEvent.java b/src/main/java/ubc/pavlab/rdp/events/OnRequestAccessEvent.java index 57247b28..6722075d 100644 --- a/src/main/java/ubc/pavlab/rdp/events/OnRequestAccessEvent.java +++ b/src/main/java/ubc/pavlab/rdp/events/OnRequestAccessEvent.java @@ -1,10 +1,12 @@ package ubc.pavlab.rdp.events; +import lombok.EqualsAndHashCode; import lombok.Getter; import org.springframework.context.ApplicationEvent; import ubc.pavlab.rdp.model.User; @Getter +@EqualsAndHashCode public class OnRequestAccessEvent extends ApplicationEvent { private User user; diff --git a/src/main/java/ubc/pavlab/rdp/events/OnUserPasswordResetEvent.java b/src/main/java/ubc/pavlab/rdp/events/OnUserPasswordResetEvent.java new file mode 100644 index 00000000..413b9cb7 --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/events/OnUserPasswordResetEvent.java @@ -0,0 +1,26 @@ +package ubc.pavlab.rdp.events; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.springframework.context.ApplicationEvent; +import ubc.pavlab.rdp.model.PasswordResetToken; +import ubc.pavlab.rdp.model.User; + +import java.util.Locale; + +@Getter +@EqualsAndHashCode +public class OnUserPasswordResetEvent extends ApplicationEvent { + + private final User user; + private final PasswordResetToken token; + private final Locale locale; + + public OnUserPasswordResetEvent( User user, PasswordResetToken token, Locale locale ) { + super( user ); + this.user = user; + this.token = token; + this.locale = locale; + } + +} diff --git a/src/main/java/ubc/pavlab/rdp/listeners/UserListener.java b/src/main/java/ubc/pavlab/rdp/listeners/UserListener.java index da04c327..05d2e9f5 100644 --- a/src/main/java/ubc/pavlab/rdp/listeners/UserListener.java +++ b/src/main/java/ubc/pavlab/rdp/listeners/UserListener.java @@ -2,11 +2,14 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionPhase; import org.springframework.transaction.event.TransactionalEventListener; import ubc.pavlab.rdp.events.OnContactEmailUpdateEvent; import ubc.pavlab.rdp.events.OnRegistrationCompleteEvent; import ubc.pavlab.rdp.events.OnRequestAccessEvent; +import ubc.pavlab.rdp.events.OnUserPasswordResetEvent; import ubc.pavlab.rdp.model.UserGene; import ubc.pavlab.rdp.services.EmailService; import ubc.pavlab.rdp.settings.ApplicationSettings; @@ -41,6 +44,15 @@ public void onRegistrationComplete( OnRegistrationCompleteEvent event ) { } } + @TransactionalEventListener + public void onUserPasswordReset( OnUserPasswordResetEvent event ) { + try { + emailService.sendResetTokenMessage( event.getUser(), event.getToken(), event.getLocale() ); + } catch ( MessagingException e ) { + log.error( MessageFormat.format( "Could not send password reset email to {0}.", event.getUser() ), e ); + } + } + @TransactionalEventListener public void onContactEmailUpdate( OnContactEmailUpdateEvent event ) { try { diff --git a/src/main/java/ubc/pavlab/rdp/model/GeneInfo.java b/src/main/java/ubc/pavlab/rdp/model/GeneInfo.java index 69853e1d..0cfbc7a6 100644 --- a/src/main/java/ubc/pavlab/rdp/model/GeneInfo.java +++ b/src/main/java/ubc/pavlab/rdp/model/GeneInfo.java @@ -2,10 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; -import org.springframework.transaction.annotation.Transactional; import javax.persistence.*; -import java.io.Serializable; import java.util.HashSet; import java.util.Set; @@ -21,7 +19,6 @@ @Index(columnList = "gene_id, taxon_id"), @Index(columnList = "symbol, taxon_id") }) @Getter -@Transactional public class GeneInfo extends Gene { @Id diff --git a/src/main/java/ubc/pavlab/rdp/services/EmailService.java b/src/main/java/ubc/pavlab/rdp/services/EmailService.java index 0303177b..eed92880 100644 --- a/src/main/java/ubc/pavlab/rdp/services/EmailService.java +++ b/src/main/java/ubc/pavlab/rdp/services/EmailService.java @@ -9,21 +9,22 @@ import javax.mail.MessagingException; import javax.servlet.http.HttpServletRequest; import java.util.Locale; +import java.util.concurrent.Future; /** * */ public interface EmailService { - void sendSupportMessage( String message, String name, User user, String userAgent, MultipartFile attachment, Locale locale ) throws MessagingException; + Future sendSupportMessage( String message, String name, User user, String userAgent, MultipartFile attachment, Locale locale ) throws MessagingException; - void sendResetTokenMessage( User user, PasswordResetToken token, Locale locale ) throws MessagingException; + Future sendResetTokenMessage( User user, PasswordResetToken token, Locale locale ) throws MessagingException; - void sendRegistrationMessage( User user, VerificationToken token, Locale locale ) throws MessagingException; + Future sendRegistrationMessage( User user, VerificationToken token, Locale locale ) throws MessagingException; - void sendContactEmailVerificationMessage( User user, VerificationToken token, Locale locale ) throws MessagingException; + Future sendContactEmailVerificationMessage( User user, VerificationToken token, Locale locale ) throws MessagingException; - void sendUserRegisteredEmail( User user ) throws MessagingException; + Future sendUserRegisteredEmail( User user ) throws MessagingException; - void sendUserGeneAccessRequest( UserGene userGene, User by, String reason ) throws MessagingException; + Future sendUserGeneAccessRequest( UserGene userGene, User by, String reason ) throws MessagingException; } diff --git a/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java index 958ae225..f081821d 100644 --- a/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java @@ -6,6 +6,8 @@ import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.util.UriComponentsBuilder; @@ -26,6 +28,8 @@ import java.time.format.FormatStyle; import java.util.Collections; import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; /** * Created by mjacobson on 19/01/18. @@ -43,8 +47,7 @@ public class EmailServiceImpl implements EmailService { @Autowired private MessageSource messageSource; - private void sendSimpleMessage( String subject, String content, InternetAddress to, InternetAddress replyTo, InternetAddress cc ) throws AddressException { - + private Future sendSimpleMessage( String subject, String content, InternetAddress to, InternetAddress replyTo, InternetAddress cc ) throws AddressException { SimpleMailMessage email = new SimpleMailMessage(); email.setSubject( subject ); @@ -58,11 +61,10 @@ private void sendSimpleMessage( String subject, String content, InternetAddress email.setCc( cc.toString() ); } - emailSender.send( email ); - + return CompletableFuture.runAsync( () -> emailSender.send( email ) ); } - private void sendMultipartMessage( String subject, String content, InternetAddress to, InternetAddress replyTo, MultipartFile attachment ) throws MessagingException { + private Future sendMultipartMessage( String subject, String content, InternetAddress to, InternetAddress replyTo, MultipartFile attachment ) throws MessagingException { MimeMessage message = emailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper( message, true ); @@ -76,11 +78,11 @@ private void sendMultipartMessage( String subject, String content, InternetAddre helper.addAttachment( attachment.getOriginalFilename(), attachment ); - emailSender.send( message ); + return CompletableFuture.runAsync( () -> emailSender.send( message ) ); } @Override - public void sendSupportMessage( String message, String name, User user, String userAgent, MultipartFile attachment, Locale locale ) throws MessagingException { + public Future sendSupportMessage( String message, String name, User user, String userAgent, MultipartFile attachment, Locale locale ) throws MessagingException { InternetAddress replyTo = user.getVerifiedContactEmail().orElseThrow( () -> new MessagingException( "Could not find a verified email address for user." ) ); String shortName = messageSource.getMessage( "rdp.site.shortname", new String[]{ siteSettings.getHostUri().toString() }, Locale.getDefault() ); String subject = messageSource.getMessage( "EmailService.sendSupportMessage.subject", new String[]{ shortName }, locale ); @@ -90,14 +92,14 @@ public void sendSupportMessage( String message, String name, User user, String u "Message: " + message + "\r\n" + "File Attached: " + ( attachment != null && !attachment.getOriginalFilename().equals( "" ) ); if ( attachment == null ) { - sendSimpleMessage( subject, content, getAdminAddress(), replyTo, null ); + return sendSimpleMessage( subject, content, getAdminAddress(), replyTo, null ); } else { - sendMultipartMessage( subject, content, getAdminAddress(), replyTo, attachment ); + return sendMultipartMessage( subject, content, getAdminAddress(), replyTo, attachment ); } } @Override - public void sendResetTokenMessage( User user, PasswordResetToken token, Locale locale ) throws MessagingException { + public Future sendResetTokenMessage( User user, PasswordResetToken token, Locale locale ) throws MessagingException { String url = UriComponentsBuilder.fromUri( siteSettings.getHostUri() ) .path( "updatePassword" ) .queryParam( "id", user.getId() ) @@ -116,11 +118,11 @@ public void sendResetTokenMessage( User user, PasswordResetToken token, Locale l String content = messageSource.getMessage( "EmailService.sendResetTokenMessage", new String[]{ user.getProfile().getName(), url, dateTimeFormatter.format( token.getExpiryDate().toInstant() ) }, locale ); - sendSimpleMessage( subject, content, to, null, null ); + return sendSimpleMessage( subject, content, to, null, null ); } @Override - public void sendRegistrationMessage( User user, VerificationToken token, Locale locale ) throws MessagingException { + public Future sendRegistrationMessage( User user, VerificationToken token, Locale locale ) throws MessagingException { String shortName = messageSource.getMessage( "rdp.site.shortname", new String[]{ siteSettings.getHostUri().toString() }, locale ); String registrationWelcome = messageSource.getMessage( "rdp.site.email.registration-welcome", new String[]{ siteSettings.getHostUri().toString(), shortName }, locale ); String registrationEnding = messageSource.getMessage( "rdp.site.email.registration-ending", new String[]{ siteSettings.getContactEmail() }, locale ); @@ -136,11 +138,11 @@ public void sendRegistrationMessage( User user, VerificationToken token, Locale String message = registrationWelcome + "\r\n\r\n" + messageSource.getMessage( "EmailService.sendRegistrationMessage", new String[]{ confirmationUrl }, locale ) + "\r\n\r\n" + registrationEnding; - sendSimpleMessage( subject, message, recipientAddress, null, null ); + return sendSimpleMessage( subject, message, recipientAddress, null, null ); } @Override - public void sendContactEmailVerificationMessage( User user, VerificationToken token, Locale locale ) throws MessagingException { + public Future sendContactEmailVerificationMessage( User user, VerificationToken token, Locale locale ) throws MessagingException { InternetAddress recipientAddress = new InternetAddress( user.getProfile().getContactEmail() ); String shortName = messageSource.getMessage( "rdp.site.shortname", new String[]{ siteSettings.getHostUri().toString() }, locale ); String subject = messageSource.getMessage( "EmailService.sendContactEmailVerificationMessage.subject", new String[]{ shortName }, locale ); @@ -151,21 +153,21 @@ public void sendContactEmailVerificationMessage( User user, VerificationToken to .encode() .toUriString(); String message = messageSource.getMessage( "EmailService.sendContactEmailVerificationMessage", new String[]{ confirmationUrl }, locale ); - sendSimpleMessage( subject, message, recipientAddress, null, null ); + return sendSimpleMessage( subject, message, recipientAddress, null, null ); } @Override - public void sendUserRegisteredEmail( User user ) throws MessagingException { + public Future sendUserRegisteredEmail( User user ) throws MessagingException { // unfortunately, there's no way to tell the dmin locale Locale locale = Locale.getDefault(); String shortname = messageSource.getMessage( "rdp.site.shortname", null, locale ); String subject = messageSource.getMessage( "EmailService.sendUserRegisteredEmail.subject", new String[]{ shortname }, locale ); String content = messageSource.getMessage( "EmailService.sendUserRegisteredEmail", new String[]{ user.getEmail() }, locale ); - sendSimpleMessage( subject, content, getAdminAddress(), null, null ); + return sendSimpleMessage( subject, content, getAdminAddress(), null, null ); } @Override - public void sendUserGeneAccessRequest( UserGene userGene, User replyTo, String reason ) throws MessagingException { + public Future sendUserGeneAccessRequest( UserGene userGene, User replyTo, String reason ) throws MessagingException { String viewUserUrl = UriComponentsBuilder.fromUri( siteSettings.getHostUri() ) .path( "userView/{userId}" ) .buildAndExpand( Collections.singletonMap( "userId", replyTo.getId() ) ) @@ -179,7 +181,7 @@ public void sendUserGeneAccessRequest( UserGene userGene, User replyTo, String r String subject = messageSource.getMessage( "EmailService.sendUserGeneAccessRequest.subject", new String[]{ shortname }, locale ); String content = messageSource.getMessage( "EmailService.sendUserGeneAccessRequest", new String[]{ replyTo.getProfile().getFullName(), userGene.getSymbol(), reason, viewUserUrl }, locale ); - sendSimpleMessage( subject, content, to, replyToAddress, getAdminAddress() ); + return sendSimpleMessage( subject, content, to, replyToAddress, getAdminAddress() ); } private InternetAddress getAdminAddress() throws AddressException { diff --git a/src/main/java/ubc/pavlab/rdp/services/LoggingEmailServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/LoggingEmailServiceImpl.java index 789f0ca3..f0006255 100644 --- a/src/main/java/ubc/pavlab/rdp/services/LoggingEmailServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/LoggingEmailServiceImpl.java @@ -15,6 +15,8 @@ import javax.servlet.http.HttpServletRequest; import java.text.MessageFormat; import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; /** * Email service implementation used for development that simply pastes the email content into the logs. @@ -28,22 +30,24 @@ public class LoggingEmailServiceImpl implements EmailService { private SiteSettings siteSettings; @Override - public void sendSupportMessage( String message, String name, User user, String userAgent, MultipartFile attachment, Locale locale ) { + public Future sendSupportMessage( String message, String name, User user, String userAgent, MultipartFile attachment, Locale locale ) { log.info( MessageFormat.format( "Support message for {0}:\n{1}", user, message ) ); + return CompletableFuture.completedFuture( null ); } @Override - public void sendResetTokenMessage( User user, PasswordResetToken token, Locale locale ) { + public Future sendResetTokenMessage( User user, PasswordResetToken token, Locale locale ) { String url = UriComponentsBuilder.fromUri( siteSettings.getHostUri() ) .path( "updatePassword" ) .queryParam( "id", user.getId() ) .queryParam( "token", token.getToken() ) .build().encode().toUriString(); log.info( MessageFormat.format( "Reset URL for {0}: {1}", user, url ) ); + return CompletableFuture.completedFuture( null ); } @Override - public void sendRegistrationMessage( User user, VerificationToken token, Locale locale ) { + public Future sendRegistrationMessage( User user, VerificationToken token, Locale locale ) { String confirmationUrl = UriComponentsBuilder.fromUri( siteSettings.getHostUri() ) .path( "registrationConfirm" ) .queryParam( "token", token.getToken() ) @@ -51,10 +55,11 @@ public void sendRegistrationMessage( User user, VerificationToken token, Locale .encode() .toUriString(); log.info( MessageFormat.format( "Confirmation URL for {0}: {1}", user, confirmationUrl ) ); + return CompletableFuture.completedFuture( null ); } @Override - public void sendContactEmailVerificationMessage( User user, VerificationToken token, Locale locale ) { + public Future sendContactEmailVerificationMessage( User user, VerificationToken token, Locale locale ) { String confirmationUrl = UriComponentsBuilder.fromUri( siteSettings.getHostUri() ) .path( "user/verify-contact-email" ) .queryParam( "token", token.getToken() ) @@ -62,15 +67,18 @@ public void sendContactEmailVerificationMessage( User user, VerificationToken to .encode() .toUriString(); log.info( MessageFormat.format( "Contact email verification URL for {0}: {1}", user, confirmationUrl ) ); + return CompletableFuture.completedFuture( null ); } @Override - public void sendUserRegisteredEmail( User user ) { + public Future sendUserRegisteredEmail( User user ) { log.info( MessageFormat.format( "{0} has been registered.", user ) ); + return CompletableFuture.completedFuture( null ); } @Override - public void sendUserGeneAccessRequest( UserGene userGene, User by, String reason ) { + public Future sendUserGeneAccessRequest( UserGene userGene, User by, String reason ) { log.info( MessageFormat.format( "{0} has been requested by {1} for: {2}.", userGene, by, reason ) ); + return CompletableFuture.completedFuture( null ); } } diff --git a/src/main/java/ubc/pavlab/rdp/services/UserService.java b/src/main/java/ubc/pavlab/rdp/services/UserService.java index 12d4fe74..92db57c9 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserService.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserService.java @@ -91,16 +91,15 @@ User updateTermsAndGenesInTaxon( User user, User updateUserProfileAndPublicationsAndOrgans( User user, Profile profile, Set publications, Set organUberonIds, Locale locale ); - PasswordResetToken createPasswordResetTokenForUser( User user ); + PasswordResetToken createPasswordResetTokenForUser( User user, Locale locale ); PasswordResetToken verifyPasswordResetToken( int userId, String token ) throws TokenException; User changePasswordByResetToken( int userId, String token, PasswordReset passwordReset ) throws TokenException; - VerificationToken createVerificationTokenForUser( User user ); + VerificationToken createVerificationTokenForUser( User user, Locale locale ); - @Transactional - VerificationToken createContactEmailVerificationTokenForUser( User user ); + VerificationToken createContactEmailVerificationTokenForUser( User user, Locale locale ); User confirmVerificationToken( String token ) throws TokenException; @@ -111,4 +110,6 @@ User updateTermsAndGenesInTaxon( User user, long computeTermOverlaps( UserTerm userTerm, Collection genes ); long computeTermFrequencyInTaxon( User user, GeneOntologyTerm term, Taxon taxon ); + + void sendGeneAccessRequest( User requestingUser, UserGene userGene, String reason ); } diff --git a/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java index b81b075f..5101acca 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java @@ -20,6 +20,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ubc.pavlab.rdp.events.OnContactEmailUpdateEvent; +import ubc.pavlab.rdp.events.OnRegistrationCompleteEvent; +import ubc.pavlab.rdp.events.OnRequestAccessEvent; +import ubc.pavlab.rdp.events.OnUserPasswordResetEvent; import ubc.pavlab.rdp.exception.TokenException; import ubc.pavlab.rdp.model.*; import ubc.pavlab.rdp.model.enums.PrivacyLevelType; @@ -523,6 +526,12 @@ public long computeTermFrequencyInTaxon( User user, GeneOntologyTerm term, Taxon .count(); } + @Override + @Transactional + public void sendGeneAccessRequest( User requestingUser, UserGene userGene, String reason ) { + eventPublisher.publishEvent( new OnRequestAccessEvent( requestingUser, userGene, reason ) ); + } + @Transactional @Override @PreAuthorize("hasPermission(#user, 'update')") @@ -562,8 +571,7 @@ public User updateUserProfileAndPublicationsAndOrgans( User user, Profile profil user.getProfile().setContactEmailVerified( true ); } else { user.getProfile().setContactEmailVerified( false ); - VerificationToken token = createContactEmailVerificationTokenForUser( user ); - eventPublisher.publishEvent( new OnContactEmailUpdateEvent( user, token, locale ) ); + VerificationToken token = createContactEmailVerificationTokenForUser( user, locale ); } } else { // contact email is unset, so we don't need to send a confirmation @@ -614,11 +622,13 @@ public User updateUserProfileAndPublicationsAndOrgans( User user, Profile profil @Transactional @Override - public PasswordResetToken createPasswordResetTokenForUser( User user ) { + public PasswordResetToken createPasswordResetTokenForUser( User user, Locale locale ) { PasswordResetToken userToken = new PasswordResetToken(); userToken.setUser( user ); userToken.updateToken( createSecureRandomToken() ); - return passwordResetTokenRepository.save( userToken ); + userToken = passwordResetTokenRepository.save( userToken ); + eventPublisher.publishEvent( new OnUserPasswordResetEvent( user, userToken, locale ) ); + return userToken; } @Override @@ -658,22 +668,26 @@ public User changePasswordByResetToken( int userId, String token, PasswordReset @Transactional @Override - public VerificationToken createVerificationTokenForUser( User user ) { + public VerificationToken createVerificationTokenForUser( User user, Locale locale ) { VerificationToken userToken = new VerificationToken(); userToken.setUser( user ); userToken.setEmail( user.getEmail() ); userToken.updateToken( createSecureRandomToken() ); - return tokenRepository.save( userToken ); + userToken = tokenRepository.save( userToken ); + eventPublisher.publishEvent( new OnRegistrationCompleteEvent( user, userToken, locale ) ); + return userToken; } @Transactional @Override - public VerificationToken createContactEmailVerificationTokenForUser( User user ) { + public VerificationToken createContactEmailVerificationTokenForUser( User user, Locale locale ) { VerificationToken userToken = new VerificationToken(); userToken.setUser( user ); userToken.setEmail( user.getProfile().getContactEmail() ); userToken.updateToken( createSecureRandomToken() ); - return tokenRepository.save( userToken ); + userToken = tokenRepository.save( userToken ); + eventPublisher.publishEvent( new OnContactEmailUpdateEvent( user, userToken, locale ) ); + return userToken; } @Override diff --git a/src/test/java/ubc/pavlab/rdp/controllers/LoginControllerTest.java b/src/test/java/ubc/pavlab/rdp/controllers/LoginControllerTest.java index 7b3c91b7..1ea1fa18 100644 --- a/src/test/java/ubc/pavlab/rdp/controllers/LoginControllerTest.java +++ b/src/test/java/ubc/pavlab/rdp/controllers/LoginControllerTest.java @@ -13,15 +13,15 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import ubc.pavlab.rdp.WebSecurityConfig; -import ubc.pavlab.rdp.events.OnRegistrationCompleteEvent; import ubc.pavlab.rdp.exception.TokenException; -import ubc.pavlab.rdp.listeners.UserListener; import ubc.pavlab.rdp.model.User; import ubc.pavlab.rdp.services.PrivacyService; import ubc.pavlab.rdp.services.UserService; import ubc.pavlab.rdp.settings.ApplicationSettings; import ubc.pavlab.rdp.settings.SiteSettings; +import java.util.Locale; + import static org.mockito.Matchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -62,9 +62,6 @@ public class LoginControllerTest { @MockBean private PermissionEvaluator permissionEvaluator; - @MockBean - UserListener userListener; - @Test public void login_thenReturnSuccess() throws Exception { mvc.perform( get( "/login" ) ) @@ -101,7 +98,8 @@ public void register_thenReturnSuccess() throws Exception { @Test public void resendConfirmation_thenReturnSuccess() throws Exception { - mvc.perform( get( "/resendConfirmation" ) ) + mvc.perform( get( "/resendConfirmation" ) + .locale( Locale.getDefault() ) ) .andExpect( status().isOk() ) .andExpect( view().name( "resendConfirmation" ) ); @@ -110,13 +108,13 @@ public void resendConfirmation_thenReturnSuccess() throws Exception { when( userService.findUserByEmailNoAuth( "foo@example.com" ) ).thenReturn( user ); mvc.perform( post( "/resendConfirmation" ) - .param( "email", "foo@example.com" ) ) + .locale( Locale.getDefault() ) + .param( "email", "foo@example.com" ) ) .andExpect( status().isOk() ) .andExpect( view().name( "resendConfirmation" ) ); verify( userService ).findUserByEmailNoAuth( "foo@example.com" ); - verify( userService ).createVerificationTokenForUser( user ); - verify( userListener ).onRegistrationComplete( any( OnRegistrationCompleteEvent.class ) ); + verify( userService ).createVerificationTokenForUser( user, Locale.getDefault() ); } @Test diff --git a/src/test/java/ubc/pavlab/rdp/controllers/PasswordControllerTest.java b/src/test/java/ubc/pavlab/rdp/controllers/PasswordControllerTest.java index 68694cde..1fdfeaaa 100644 --- a/src/test/java/ubc/pavlab/rdp/controllers/PasswordControllerTest.java +++ b/src/test/java/ubc/pavlab/rdp/controllers/PasswordControllerTest.java @@ -22,6 +22,8 @@ import ubc.pavlab.rdp.services.UserService; import ubc.pavlab.rdp.settings.SiteSettings; +import java.util.Locale; + import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; @@ -78,13 +80,13 @@ public void forgotPassword_thenReturnSuccess() throws Exception { when( userService.findUserByEmailNoAuth( "foo@example.com" ) ).thenReturn( user ); mvc.perform( post( "/forgotPassword" ) - .param( "email", "foo@example.com" ) ) + .locale( Locale.getDefault() ) + .param( "email", "foo@example.com" ) ) .andExpect( status().isOk() ) .andExpect( view().name( "forgotPassword" ) ) .andExpect( model().attribute( "error", false ) ); - verify( userService ).createPasswordResetTokenForUser( eq( user ) ); - verify( emailService ).sendResetTokenMessage( eq( user ), any(), any() ); + verify( userService ).createPasswordResetTokenForUser( eq( user ), eq( Locale.getDefault() ) ); } @Test diff --git a/src/test/java/ubc/pavlab/rdp/controllers/SearchControllerTest.java b/src/test/java/ubc/pavlab/rdp/controllers/SearchControllerTest.java index 0c971e73..249d5a20 100644 --- a/src/test/java/ubc/pavlab/rdp/controllers/SearchControllerTest.java +++ b/src/test/java/ubc/pavlab/rdp/controllers/SearchControllerTest.java @@ -351,16 +351,11 @@ public void requestAccess_thenReturnSuccess() throws Exception { verify( userService ).anonymizeUserGene( userGene ); mvc.perform( post( "/search/gene/by-anonymous-id/{anonymousId}/request-access", anonymizedUserGene.getAnonymousId() ) - .param( "reason", "Because." ) ) + .param( "reason", "Because." ) ) .andExpect( status().is3xxRedirection() ) .andExpect( redirectedUrl( "/search" ) ) .andExpect( flash().attributeExists( "message" ) ); - ArgumentCaptor captor = ArgumentCaptor.forClass( OnRequestAccessEvent.class ); - verify( userListener ).onGeneRequestAccess( captor.capture() ); - assertThat( captor.getValue() ) - .hasFieldOrPropertyWithValue( "user", user ) - .hasFieldOrPropertyWithValue( "object", userGene ) - .hasFieldOrPropertyWithValue( "reason", "Because." ); + verify( userService ).sendGeneAccessRequest( user, userGene, "Because." ); } @Test diff --git a/src/test/java/ubc/pavlab/rdp/controllers/UserControllerTest.java b/src/test/java/ubc/pavlab/rdp/controllers/UserControllerTest.java index ecd0badf..c234f10d 100644 --- a/src/test/java/ubc/pavlab/rdp/controllers/UserControllerTest.java +++ b/src/test/java/ubc/pavlab/rdp/controllers/UserControllerTest.java @@ -9,7 +9,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.mockito.internal.util.collections.Sets; import org.springframework.beans.factory.annotation.Autowired; @@ -26,9 +25,7 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.multipart.MultipartFile; import ubc.pavlab.rdp.WebSecurityConfig; -import ubc.pavlab.rdp.events.OnContactEmailUpdateEvent; import ubc.pavlab.rdp.exception.TokenException; -import ubc.pavlab.rdp.listeners.UserListener; import ubc.pavlab.rdp.model.*; import ubc.pavlab.rdp.model.enums.Aspect; import ubc.pavlab.rdp.model.enums.PrivacyLevelType; @@ -120,9 +117,6 @@ public class UserControllerTest { @MockBean private EmailService emailService; - @MockBean - private UserListener userListener; - @Before public void setUp() { when( applicationSettings.getEnabledTiers() ).thenReturn( Lists.newArrayList( "TIER1", "TIER2", "TIER3" ) ); @@ -738,15 +732,12 @@ public void givenLoggedIn_whenResendContactEmailVerification_thenRedirect3xx() t User user = createUser( 1 ); VerificationToken token = createContactEmailVerificationToken( user, "1234" ); when( userService.findCurrentUser() ).thenReturn( user ); - when( userService.createContactEmailVerificationTokenForUser( user ) ).thenReturn( token ); - mvc.perform( post( "/user/resend-contact-email-verification" ) ) + when( userService.createContactEmailVerificationTokenForUser( user, Locale.getDefault() ) ).thenReturn( token ); + mvc.perform( post( "/user/resend-contact-email-verification" ) + .locale( Locale.getDefault() ) ) .andExpect( status().is3xxRedirection() ) .andExpect( redirectedUrl( "/user/profile" ) ) .andExpect( flash().attributeExists( "message" ) ); - verify( userService ).createContactEmailVerificationTokenForUser( user ); - ArgumentCaptor eventCaptor = ArgumentCaptor.forClass( OnContactEmailUpdateEvent.class ); - verify( userListener ).onContactEmailUpdate( eventCaptor.capture() ); - assertThat( eventCaptor.getValue().getUser() ).isEqualTo( user ); - assertThat( eventCaptor.getValue().getToken() ).isEqualTo( token ); + verify( userService ).createContactEmailVerificationTokenForUser( user, Locale.getDefault() ); } } diff --git a/src/test/java/ubc/pavlab/rdp/services/EmailServiceImplTest.java b/src/test/java/ubc/pavlab/rdp/services/EmailServiceImplTest.java index a6a9e0a6..07ea0b12 100644 --- a/src/test/java/ubc/pavlab/rdp/services/EmailServiceImplTest.java +++ b/src/test/java/ubc/pavlab/rdp/services/EmailServiceImplTest.java @@ -24,6 +24,7 @@ import javax.mail.MessagingException; import java.net.URI; import java.util.Locale; +import java.util.concurrent.ExecutionException; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.verify; @@ -59,9 +60,9 @@ public void setUp() { } @Test - public void sendUserRegistered_thenSucceed() throws MessagingException { + public void sendUserRegistered_thenSucceed() throws MessagingException, ExecutionException, InterruptedException { User user = createUser( 1 ); - emailService.sendUserRegisteredEmail( user ); + emailService.sendUserRegisteredEmail( user ).get(); ArgumentCaptor mailMessageCaptor = ArgumentCaptor.forClass( SimpleMailMessage.class ); verify( emailSender ).send( mailMessageCaptor.capture() ); assertThat( mailMessageCaptor.getValue() ) @@ -73,10 +74,10 @@ public void sendUserRegistered_thenSucceed() throws MessagingException { } @Test - public void sendSupportMessage_thenSucceed() throws MessagingException { + public void sendSupportMessage_thenSucceed() throws MessagingException, ExecutionException, InterruptedException { User user = createUser( 1 ); user.setEnabled( true ); - emailService.sendSupportMessage( "I need help!", "John Doe", user, "Google Chrome", null, Locale.getDefault() ); + emailService.sendSupportMessage( "I need help!", "John Doe", user, "Google Chrome", null, Locale.getDefault() ).get(); ArgumentCaptor mailMessageCaptor = ArgumentCaptor.forClass( SimpleMailMessage.class ); verify( emailSender ).send( mailMessageCaptor.capture() ); assertThat( mailMessageCaptor.getValue() ) @@ -107,10 +108,10 @@ public void sendResetTokenMessage_thenSucceed() throws MessagingException { } @Test - public void sendRegistrationMessageMessage_thenSucceed() throws MessagingException { + public void sendRegistrationMessageMessage_thenSucceed() throws MessagingException, ExecutionException, InterruptedException { User user = createUser( 1 ); VerificationToken token = createVerificationToken( user, "1234" ); - emailService.sendRegistrationMessage( user, token, Locale.getDefault() ); + emailService.sendRegistrationMessage( user, token, Locale.getDefault() ).get(); ArgumentCaptor mailMessageCaptor = ArgumentCaptor.forClass( SimpleMailMessage.class ); verify( emailSender ).send( mailMessageCaptor.capture() ); assertThat( mailMessageCaptor.getValue() ) @@ -122,11 +123,11 @@ public void sendRegistrationMessageMessage_thenSucceed() throws MessagingExcepti } @Test - public void sendContactEmailVerificationMessage_thenSucceed() throws MessagingException { + public void sendContactEmailVerificationMessage_thenSucceed() throws MessagingException, ExecutionException, InterruptedException { User user = createUser( 1 ); user.getProfile().setContactEmail( "foo@example.com" ); VerificationToken token = createContactEmailVerificationToken( user, "1234" ); - emailService.sendContactEmailVerificationMessage( user, token, Locale.getDefault() ); + emailService.sendContactEmailVerificationMessage( user, token, Locale.getDefault() ).get(); ArgumentCaptor mailMessageCaptor = ArgumentCaptor.forClass( SimpleMailMessage.class ); verify( emailSender ).send( mailMessageCaptor.capture() ); assertThat( mailMessageCaptor.getValue() ) @@ -138,11 +139,11 @@ public void sendContactEmailVerificationMessage_thenSucceed() throws MessagingEx } @Test - public void sendContactEmailVerificationMessage_whenTokenContainsInvalidCharacter_thenSucceed() throws MessagingException { + public void sendContactEmailVerificationMessage_whenTokenContainsInvalidCharacter_thenSucceed() throws MessagingException, ExecutionException, InterruptedException { User user = createUser( 1 ); user.getProfile().setContactEmail( "foo@example.com" ); VerificationToken token = createContactEmailVerificationToken( user, "1234+" ); - emailService.sendContactEmailVerificationMessage( user, token, Locale.getDefault() ); + emailService.sendContactEmailVerificationMessage( user, token, Locale.getDefault() ).get(); ArgumentCaptor mailMessageCaptor = ArgumentCaptor.forClass( SimpleMailMessage.class ); verify( emailSender ).send( mailMessageCaptor.capture() ); assertThat( mailMessageCaptor.getValue() ) @@ -154,7 +155,7 @@ public void sendContactEmailVerificationMessage_whenTokenContainsInvalidCharacte } @Test - public void sendUserGeneAccessRequest_thenSucceed() throws MessagingException { + public void sendUserGeneAccessRequest_thenSucceed() throws MessagingException, ExecutionException, InterruptedException { User user = createUser( 1 ); user.getProfile().setContactEmail( "foo@example.com" ); user.getProfile().setContactEmailVerified( true ); @@ -162,7 +163,7 @@ public void sendUserGeneAccessRequest_thenSucceed() throws MessagingException { user2.getProfile().setContactEmail( "bar@example.com" ); user2.getProfile().setContactEmailVerified( true ); UserGene userGene = createUserGene( 1, createGene( 1, createTaxon( 1 ) ), user2, TierType.TIER1, PrivacyLevelType.PRIVATE ); - emailService.sendUserGeneAccessRequest( userGene, user, "Because." ); + emailService.sendUserGeneAccessRequest( userGene, user, "Because." ).get(); ArgumentCaptor mailMessageCaptor = ArgumentCaptor.forClass( SimpleMailMessage.class ); verify( emailSender ).send( mailMessageCaptor.capture() ); SimpleMailMessage mailMessage = mailMessageCaptor.getValue(); diff --git a/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java b/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java index 754a6efe..fff2dacb 100644 --- a/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java +++ b/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java @@ -5,6 +5,7 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.mockito.internal.util.collections.Sets; import org.springframework.beans.factory.annotation.Autowired; @@ -21,6 +22,9 @@ import org.springframework.test.context.junit4.SpringRunner; import ubc.pavlab.rdp.WebMvcConfig; import ubc.pavlab.rdp.events.OnContactEmailUpdateEvent; +import ubc.pavlab.rdp.events.OnRegistrationCompleteEvent; +import ubc.pavlab.rdp.events.OnRequestAccessEvent; +import ubc.pavlab.rdp.events.OnUserPasswordResetEvent; import ubc.pavlab.rdp.exception.TokenException; import ubc.pavlab.rdp.listeners.UserListener; import ubc.pavlab.rdp.model.*; @@ -32,6 +36,7 @@ import ubc.pavlab.rdp.security.PermissionEvaluatorImpl; import ubc.pavlab.rdp.settings.ApplicationSettings; +import javax.mail.MessagingException; import javax.validation.ValidationException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; @@ -678,15 +683,16 @@ public void updateUserProfileAndPublicationsAndOrgans_whenResearcherCategoriesAr } @Test - public void createPasswordResetTokenForUser_hasCorrectExpiration() { + public void createPasswordResetTokenForUser_hasCorrectExpiration() throws MessagingException { User user = createUser( 1 ); - PasswordResetToken passwordResetToken = userService.createPasswordResetTokenForUser( user ); + PasswordResetToken passwordResetToken = userService.createPasswordResetTokenForUser( user, Locale.getDefault() ); Instant lowerBound = Instant.now().plus( 2, ChronoUnit.HOURS ).minus( 1, ChronoUnit.MINUTES ); Instant upperBound = Instant.now().plus( 2, ChronoUnit.HOURS ).plus( 1, ChronoUnit.MINUTES ); // one minute tolerance assertThat( passwordResetToken.getExpiryDate().toInstant() ).isBetween( lowerBound, upperBound ); + verify( userListener ).onUserPasswordReset( new OnUserPasswordResetEvent( user, passwordResetToken, Locale.getDefault() ) ); } @Test @@ -721,14 +727,14 @@ public void verifyPasswordResetToken_whenExpiredToken_thenThrowTokenException() @Test public void createVerificationTokenForUser_hasCorrectExpiration() { User user = createUser( 1 ); - VerificationToken verificationToken = userService.createVerificationTokenForUser( user ); + VerificationToken verificationToken = userService.createVerificationTokenForUser( user, Locale.getDefault() ); Instant lowerBound = Instant.now().plus( 24, ChronoUnit.HOURS ).minus( 1, ChronoUnit.MINUTES ); Instant upperBound = Instant.now().plus( 24, ChronoUnit.HOURS ).plus( 1, ChronoUnit.MINUTES ); // one minute tolerance assertThat( verificationToken.getExpiryDate().toInstant() ).isBetween( lowerBound, upperBound ); - + verify( userListener ).onRegistrationComplete( any( OnRegistrationCompleteEvent.class ) ); } @Test @@ -1297,6 +1303,20 @@ public void anonymizeUserGene_thenReturnAnonymizedUserGene() { .isEqualTo( userGene ); } + @Test + public void sendGeneAccessRequest_thenTriggerOnRequestAccessEvent() { + User user = createUser( 1 ); + Taxon taxon = createTaxon( 1 ); + UserGene userGene = createUserGene( 1, createGene( 1, taxon ), user, TierType.TIER1, PrivacyLevelType.PRIVATE ); + userService.sendGeneAccessRequest( user, userGene, "Because." ); + ArgumentCaptor captor = ArgumentCaptor.forClass( OnRequestAccessEvent.class ); + verify( userListener ).onGeneRequestAccess( captor.capture() ); + assertThat( captor.getValue() ) + .hasFieldOrPropertyWithValue( "user", user ) + .hasFieldOrPropertyWithValue( "object", userGene ) + .hasFieldOrPropertyWithValue( "reason", "Because." ); + } + private GeneOntologyTermInfo createTermWithGenes( String id, GeneInfo... genes ) { GeneOntologyTermInfo term = createTerm( id ); when( goService.getDirectGenes( term ) ).thenReturn( Arrays.stream( genes ).map( GeneInfo::getGeneId ).collect( Collectors.toSet() ) );