diff --git a/src/main/java/de/tum/cit/aet/application/service/ApplicationService.java b/src/main/java/de/tum/cit/aet/application/service/ApplicationService.java index e5d7a43a22..4795738a57 100644 --- a/src/main/java/de/tum/cit/aet/application/service/ApplicationService.java +++ b/src/main/java/de/tum/cit/aet/application/service/ApplicationService.java @@ -340,29 +340,34 @@ private void confirmApplicationToProfessor(Application application) { } /** - * Withdraws an application by setting its state to WITHDRAWN. + * Reverts a submitted application back to {@link ApplicationState#SAVED} so + * the applicant can edit and resubmit it. Only applications currently in + * {@link ApplicationState#SENT} can be unsubmitted, and only while the job's + * deadline has not yet passed. * - * @param applicationId the UUID of the application to withdraw + * @param applicationId the UUID of the application to unsubmit + * @throws OperationNotAllowedException if the application is not in SENT state + * or the job deadline has already passed */ public void withdrawApplication(UUID applicationId) { Application application = assertCanManageApplication(applicationId); - User user = application.getApplicant().getUser(); Job job = application.getJob(); - application.setState(ApplicationState.WITHDRAWN); - application = applicationRepository.save(application); + if (application.getState() != ApplicationState.SENT) { + throw new OperationNotAllowedException( + "Application " + applicationId + " cannot be unsubmitted from state " + application.getState() + ); + } - referenceRequestService.cancelPendingForWithdrawnApplication(application); + LocalDate endDate = job.getEndDate(); + if (endDate != null && endDate.isBefore(LocalDate.now())) { + throw new OperationNotAllowedException("Application " + applicationId + " cannot be unsubmitted after the job deadline"); + } - Email email = Email.builder() - .to(user) - .language(Language.fromCode(user.getSelectedLanguage())) - .emailType(EmailType.APPLICATION_WITHDRAWN) - .content(application) - .researchGroup(job.getResearchGroup()) - .build(); + application.setState(ApplicationState.SAVED); + application = applicationRepository.save(application); - sender.sendAsync(email); + referenceRequestService.cancelPendingForWithdrawnApplication(application); } /** diff --git a/src/main/java/de/tum/cit/aet/reference/service/ReferenceRequestService.java b/src/main/java/de/tum/cit/aet/reference/service/ReferenceRequestService.java index 4ef999f526..48e4a01fab 100644 --- a/src/main/java/de/tum/cit/aet/reference/service/ReferenceRequestService.java +++ b/src/main/java/de/tum/cit/aet/reference/service/ReferenceRequestService.java @@ -228,6 +228,11 @@ public void removeFromApplication(UUID applicationId, UUID referenceId) { * Generates and persists a fresh token for each pending entry on the application and dispatches * the invitation email. Must be called from a transactional context — the caller's transaction * keeps {@code application.job} / {@code application.job.researchGroup} attached for lazy access. + *

+ * Referees never invited yet are invited for the first time. Referees whose request was cancelled + * by an earlier withdrawal are invited again with a fresh token, so the link they were sent before + * the withdrawal stays dead. Referees who already submitted, declined or let their link expire are + * left alone, so resubmitting never asks them a second time. * * @param application the application whose referees should be notified */ @@ -239,7 +244,9 @@ public void dispatchInvitations(Application application) { application.getApplicationId() ); for (ReferenceRequest entry : entries) { - if (entry.getStatus() != ReferenceRequestStatus.ADDED || entry.getTokenHash() != null) { + boolean neverInvited = entry.getStatus() == ReferenceRequestStatus.ADDED && entry.getTokenHash() == null; + boolean cancelledByWithdrawal = entry.getStatus() == ReferenceRequestStatus.CANCELLED; + if (!neverInvited && !cancelledByWithdrawal) { continue; } issueInvitation(application, entry); diff --git a/src/main/webapp/app/application/application-creation/application-creation-form/application-creation-form.component.html b/src/main/webapp/app/application/application-creation/application-creation-form/application-creation-form.component.html index 3ed0d02189..0b97e7915b 100644 --- a/src/main/webapp/app/application/application-creation/application-creation-form/application-creation-form.component.html +++ b/src/main/webapp/app/application/application-creation/application-creation-form/application-creation-form.component.html @@ -1,7 +1,7 @@