@@ -591,11 +591,22 @@ public boolean handlePost(SignupForm signupForm, BindException errors) throws Ex
591591 return false ;
592592 }
593593
594- if (! createUserAndSendEmail ( signupForm , email , errors ))
594+ try
595595 {
596+ createUserAndSendEmail (signupForm , email );
597+ }
598+ catch (MessagingException | ConfigurationException e )
599+ {
600+ errors .reject (ERROR_MSG , sendEmailErrorMessage (getContainer ()));
601+ if (e .getMessage () != null )
602+ {
603+ errors .reject (ERROR_MSG , e .getMessage ());
604+ }
596605 return false ;
597606 }
598607
608+ clearCaptcha ();
609+
599610 // Re-render the JSP with the CONFIRMATION_SENT message.
600611 signupForm .setNewSignUp (false );
601612 return false ;
@@ -635,14 +646,15 @@ private void validateSignupForm(SignupForm form, Errors errors)
635646 {
636647 errors .reject (ERROR_MSG , "Confirm email cannot be blank." );
637648 }
638- else if (form .getEmail () != null && !form .getEmail ().equals (form .getEmailConfirm ()))
649+ else if (! StringUtils . isBlank ( form .getEmail ()) && !form .getEmail ().equalsIgnoreCase (form .getEmailConfirm ()))
639650 {
640651 errors .reject (ERROR_MSG , "Email addresses do not match." );
641652 }
642653 }
643654
644- // On success returns null and clears the session attribute so the captcha cannot be replayed.
645- // On failure return a user-facing error message.
655+ // On success returns null. On failure returns a user-facing error message.
656+ // Does not clear the session attribute — callers clear it after the full operation
657+ // succeeds so the user can retry with the same captcha if a later step fails.
646658 // Logging matches LoginController's RegisterUserAction.
647659 private String verifyCaptcha (String submittedText , String emailForLogging )
648660 {
@@ -658,10 +670,14 @@ private String verifyCaptcha(String submittedText, String emailForLogging)
658670 _log .warn ("Captcha text did not match for signup attempt for {}" , emailForLogging );
659671 return "Verification text does not match, please retry." ;
660672 }
661- session .removeAttribute (LabKeyKaptchaServlet .SESSION_KEY_VALUE );
662673 return null ;
663674 }
664675
676+ private void clearCaptcha ()
677+ {
678+ getViewContext ().getRequest ().getSession (true ).removeAttribute (LabKeyKaptchaServlet .SESSION_KEY_VALUE );
679+ }
680+
665681 // Returns a parsed ValidEmail, or null if the address is invalid (errors populated).
666682 // Uses EmailValidator first because ValidEmail's constructor does not throw on bare
667683 // strings like "foo" - it silently appends the server's default domain.
@@ -685,34 +701,21 @@ private ValidEmail parseAndValidateEmail(SignupForm form, Errors errors)
685701 }
686702
687703 // Creates (or reuses) a TempUser row and sends the confirmation email in a single
688- // transaction. On send failure the transaction is rolled back so a freshly inserted
689- // TempUser row does not persist when the user never received a confirmation link.
690- private boolean createUserAndSendEmail (SignupForm form , ValidEmail email , Errors errors ) throws java .sql .SQLException
704+ // transaction. On send failure the exception propagates and the transaction rolls back
705+ // automatically so a freshly inserted TempUser row does not persist.
706+ private void createUserAndSendEmail (SignupForm form , ValidEmail email )
707+ throws MessagingException , ConfigurationException , java .sql .SQLException
691708 {
692709 try (DbScope .Transaction transaction = SignUpManager .getSchema ().getScope ().ensureTransaction ())
693710 {
694711 TempUser tempUser = getTempUser (form , email );
695712 ActionURL confirmationUrl = getConfirmationURL (getContainer (), email , tempUser .getKey ());
696- try
697- {
698- User mockUser = new User ();
699- mockUser .setEmail (email .getEmailAddress ());
700- SecurityManager .sendEmail (getContainer (), mockUser ,
701- SecurityManager .getRegistrationMessage (null , false ),
702- email .getEmailAddress (), confirmationUrl );
703- }
704- catch (MessagingException | ConfigurationException e )
705- {
706- String systemEmail = LookAndFeelProperties .getInstance (getContainer ()).getSystemEmailAddress ();
707- errors .reject (ERROR_MSG , "Could not send new user registration email. Please contact your server administrator at " + systemEmail );
708- if (e .getMessage () != null )
709- {
710- errors .reject (ERROR_MSG , e .getMessage ());
711- }
712- return false ;
713- }
713+ User mockUser = new User ();
714+ mockUser .setEmail (email .getEmailAddress ());
715+ SecurityManager .sendEmail (getContainer (), mockUser ,
716+ SecurityManager .getRegistrationMessage (null , false ),
717+ email .getEmailAddress (), confirmationUrl );
714718 transaction .commit ();
715- return true ;
716719 }
717720 }
718721
@@ -723,6 +726,12 @@ private static List<String> errorsToMessages(Errors errors)
723726 .toList ();
724727 }
725728
729+ private static String sendEmailErrorMessage (Container container )
730+ {
731+ return "Could not send new user registration email. Please contact your server administrator at "
732+ + LookAndFeelProperties .getInstance (container ).getSystemEmailAddress ();
733+ }
734+
726735 public static ActionURL getConfirmationURL (Container c , ValidEmail email , String key )
727736 {
728737 ActionURL url = new ActionURL (ConfirmAction .class , c );
@@ -911,13 +920,25 @@ public ApiResponse execute(SignupForm signupForm, BindException errors) throws E
911920 return response ;
912921 }
913922
914- if (!createUserAndSendEmail (signupForm , email , errors ))
923+ try
924+ {
925+ createUserAndSendEmail (signupForm , email );
926+ }
927+ catch (MessagingException | ConfigurationException e )
915928 {
916929 response .put ("status" , "ERROR" );
917- response .put ("error_message" , errorsToMessages (errors ));
930+ List <String > messages = new ArrayList <>();
931+ messages .add (sendEmailErrorMessage (getContainer ()));
932+ if (e .getMessage () != null )
933+ {
934+ messages .add (e .getMessage ());
935+ }
936+ response .put ("error_message" , messages );
918937 return response ;
919938 }
920939
940+ clearCaptcha ();
941+
921942 response .put ("status" , "USER_ADDED" );
922943 return response ;
923944 }
0 commit comments