From 311d77fcb2a18c6bc926970569c1a369da62a91b Mon Sep 17 00:00:00 2001 From: akastijn Date: Sat, 27 Sep 2025 20:00:44 +0200 Subject: [PATCH] Enhance staff application flow with email verification checks, refined error handling, and improved user feedback in frontend and backend. --- .../forms/ApplicationController.java | 62 ++++++++----------- .../staff-application.component.html | 45 ++++++++------ .../staff-application.component.scss | 10 +++ .../staff-application.component.ts | 11 ++-- .../schemas/forms/staff_apply/staff_apply.yml | 1 - 5 files changed, 69 insertions(+), 60 deletions(-) diff --git a/backend/src/main/java/com/alttd/altitudeweb/controllers/forms/ApplicationController.java b/backend/src/main/java/com/alttd/altitudeweb/controllers/forms/ApplicationController.java index 3024f2c..9232d52 100644 --- a/backend/src/main/java/com/alttd/altitudeweb/controllers/forms/ApplicationController.java +++ b/backend/src/main/java/com/alttd/altitudeweb/controllers/forms/ApplicationController.java @@ -38,45 +38,37 @@ public class ApplicationController implements ApplicationsApi { public ResponseEntity submitStaffApplication(StaffApplicationDto staffApplicationDto) { UUID userUuid = AuthenticatedUuid.getAuthenticatedUserUuid(); + String email = staffApplicationDto.getEmail() == null ? null : staffApplicationDto.getEmail().toLowerCase(); + Optional optionalEmail = fetchEmailVerification(userUuid, email); + if (optionalEmail.isEmpty() || !optionalEmail.get().verified()) { + log.warn("User {} attempted to submit an application without a verified email {}", userUuid, email); + return ResponseEntity.badRequest().build(); + } + + // Map and persist application StaffApplication application = staffApplicationDataMapper.map(userUuid, staffApplicationDto); saveApplication(application); - Optional optionalEmail = fetchEmailVerification(userUuid, application.email()); - boolean verified = optionalEmail.map(EmailVerification::verified).orElse(false); - - boolean success = true; - if (verified) { - // Send mail first; only if sent, send to Discord, then mark as sent - boolean mailSent = false; - try { - mailSent = staffApplicationMail.sendApplicationEmail(application); - } catch (Exception e) { - log.error("Error while sending staff application email for {}", application.id(), e); - success = false; + try { + if (!staffApplicationMail.sendApplicationEmail(application)) { + log.warn("Failed to send staff application email for {}", application.id()); + return ResponseEntity.internalServerError().build(); } - - if (mailSent) { - try { - staffApplicationDiscord.sendApplicationToDiscord(application); - } catch (Exception e) { - log.error("Failed to send staff application {} to Discord", application.id(), e); - success = false; - } - } else { - success = false; - } - - if (success) { - markAsSent(application.id()); - } - } - - if (verified && !success) { + } catch (Exception e) { + log.error("Error while sending staff application email for {}", application.id(), e); return ResponseEntity.internalServerError().build(); } - FormResponseDto response = buildResponse(application, verified); - return ResponseEntity.status(201).body(response); + try { + staffApplicationDiscord.sendApplicationToDiscord(application); + } catch (Exception e) { + log.error("Failed to send staff application {} to Discord", application.id(), e); + return ResponseEntity.internalServerError().build(); + } + markAsSent(application.id()); + + FormResponseDto response = buildResponse(application); + return ResponseEntity.status(200).body(response); } private void saveApplication(StaffApplication application) { @@ -110,10 +102,8 @@ public class ApplicationController implements ApplicationsApi { .runQuery(sqlSession -> sqlSession.getMapper(StaffApplicationMapper.class).markAsSent(applicationId)); } - private FormResponseDto buildResponse(StaffApplication application, boolean verified) { - String message = verified - ? "Your staff application has been submitted. You will be notified when it has been reviewed." - : "Application created. Please verify your email to complete submission."; + private FormResponseDto buildResponse(StaffApplication application) { + String message = "Your staff application has been submitted. You will be notified when it has been reviewed."; return new FormResponseDto( application.id().toString(), message, diff --git a/frontend/src/app/pages/forms/staff-application/staff-application.component.html b/frontend/src/app/pages/forms/staff-application/staff-application.component.html index 395e821..8064d54 100644 --- a/frontend/src/app/pages/forms/staff-application/staff-application.component.html +++ b/frontend/src/app/pages/forms/staff-application/staff-application.component.html @@ -67,7 +67,14 @@
check - You have validated your email previously, and can continue to the next page! + You have validated your email previously. + +
+ } @else { +
+ + close + You have not used this email address before. Before going to the next page you will be asked to verify it.
} @@ -107,7 +114,8 @@
- I confirm that I meet the PC requirements (able to record video at 30fps 720p or higher, and able to talk in voice chat) + I confirm that I meet the PC requirements (able to record video at 30fps 720p or higher, and able + to talk in voice chat) @if (form.controls.meetsRequirements.invalid && form.controls.meetsRequirements.touched) { @@ -172,7 +180,8 @@
@for (day of availableDays; track day) { -
+
{{ day }}
} @@ -188,9 +197,9 @@ Available times (Your timezone: {{ userTimezone }}) + formControlName="availableTimes" + placeholder="e.g., 6PM-10PM weekdays, 2PM-8PM weekends" + rows="2"> @if (form.controls.availableTimes.invalid && form.controls.availableTimes.touched) { Available times are required @@ -215,9 +224,9 @@ Previous experience (here or in other relevant places) + formControlName="previousExperience" + placeholder="Describe your previous experience" + rows="4"> @if (form.controls.previousExperience.invalid && form.controls.previousExperience.touched) { @if (form.controls.previousExperience.errors?.['required']) { @@ -233,9 +242,9 @@ Experience with plugins that players use on our server + formControlName="pluginExperience" + placeholder="Describe your experience with our server plugins" + rows="4"> @if (form.controls.pluginExperience.invalid && form.controls.pluginExperience.touched) { @if (form.controls.pluginExperience.errors?.['required']) { @@ -251,9 +260,9 @@ What do you believe the expectations of a moderator are? + formControlName="moderatorExpectations" + placeholder="Describe what you think a moderator should do" + rows="4"> @if (form.controls.moderatorExpectations.invalid && form.controls.moderatorExpectations.touched) { @if (form.controls.moderatorExpectations.errors?.['required']) { @@ -269,9 +278,9 @@ Additional Information (Optional) + formControlName="additionalInfo" + placeholder="Any additional information you'd like to share" + rows="4">