Compare commits

...

5 Commits

Author SHA1 Message Date
Teriuihi caabe7b923 Refactor form submission to use dynamic Discord URLs and emails
Updated form classes to return Optional URLs for Discord bot submissions. Refactored VerifyController to handle these Optionals and improved error handling when sending forms. Added receiver email method in form classes for more flexible form submissions.
2024-08-07 00:36:22 +02:00
Teriuihi f972436717 Add getDiscordBotUrl method to form classes
Implemented getDiscordBotUrl in form classes for dynamic URL handling. Updated VerifyController to use this method for constructing Discord bot URIs. This enhances flexibility and maintainability in form submission handling.
2024-08-07 00:01:15 +02:00
Teriuihi 2ad194fab2 Update Jackson config and refactor JSON handling
Introduced Jackson dependencies to replace Gson for JSON processing. Updated application properties and controllers to handle Jackson-specific exceptions. Refactored form serialization to use Jackson's `ObjectMapper` for better date handling and consistency.
2024-08-06 23:58:15 +02:00
Teriuihi 2c3cb48667 Add REST annotations and refactor properties file handling
Introduced `@RestController` and `@RequestMapping` in `StaffAppController` for standardized API endpoints. Refactored properties file handling in `PropertiesLoader` and `PropertiesWriter` to simplify file creation logic.
2024-08-06 23:17:06 +02:00
Teriuihi 04088c20e5 Update CORS allowed origins configuration
Consolidated the allowed origins into a single `allowedOrigins` call. This ensures both local and production environments are correctly configured for CORS.
2024-08-06 23:16:38 +02:00
13 changed files with 181 additions and 49 deletions

5
.gitignore vendored
View File

@ -39,4 +39,7 @@ bin/
.vscode/
### Mac OS ###
.DS_Store
.DS_Store
*.bat
config/

View File

@ -4,16 +4,8 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="ce59df2a-8d56-446a-867b-80e627daf479" name="Changes" comment="Update URI to point to Discord bot endpoint&#10;&#10;Changed the URI in VerifyController to use the Discord bot's endpoint for form submission. This adjustment is part of the process to route form data correctly through the specified internal service.">
<change afterPath="$PROJECT_DIR$/src/main/java/com/alttd/forms/apply/StaffAppController.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/com/alttd/forms/apply/StaffAppFormData.java" afterDir="false" />
<list default="true" id="ce59df2a-8d56-446a-867b-80e627daf479" name="Changes" comment="Add getDiscordBotUrl method to form classes&#10;&#10;Implemented getDiscordBotUrl in form classes for dynamic URL handling. Updated VerifyController to use this method for constructing Discord bot URIs. This enhances flexibility and maintainability in form submission handling.">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/com/alttd/forms/contact/ContactController.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/alttd/forms/contact/ContactController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/com/alttd/forms/contact/ContactFormData.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/alttd/forms/contact/ContactFormData.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/com/alttd/forms/contact/StoreFormQuery.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/alttd/forms/form/StoreFormQuery.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/com/alttd/forms/form/Form.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/alttd/forms/form/Form.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/resources/application.properties" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/resources/application.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/test/java/TestForm.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/test/java/TestForm.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -146,7 +138,7 @@
<recent name="com.alttd.forms.apply" />
</key>
</component>
<component name="RunManager" selected="Gradle.TestForm">
<component name="RunManager" selected="Spring Boot.Main">
<configuration name="TestForm" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
<ExternalSystemSettings>
<option name="executionName" />
@ -371,7 +363,7 @@
<workItem from="1722786481232" duration="617000" />
<workItem from="1722801254695" duration="6135000" />
<workItem from="1722879625782" duration="358000" />
<workItem from="1722973564053" duration="2026000" />
<workItem from="1722973564053" duration="6695000" />
</task>
<task id="LOCAL-00001" summary="Initial commit for site for forms">
<option name="closed" value="true" />
@ -493,7 +485,71 @@
<option name="project" value="LOCAL" />
<updated>1722812932077</updated>
</task>
<option name="localTasksCounter" value="16" />
<task id="LOCAL-00016" summary="Rename StoreFormQuery package to forms.form&#10;&#10;Updated the package name for consistency and better categorization. Adjusted imports in related test files to reflect the new package structure.">
<option name="closed" value="true" />
<created>1722975667414</created>
<option name="number" value="00016" />
<option name="presentableId" value="LOCAL-00016" />
<option name="project" value="LOCAL" />
<updated>1722975667414</updated>
</task>
<task id="LOCAL-00017" summary="Refactor HTML generation in ContactFormData&#10;&#10;Extract the HTML generation logic to a reusable method in the Form class. This change reduces code duplication and enhances maintainability by centralizing the table generation functionality.">
<option name="closed" value="true" />
<created>1722975690755</created>
<option name="number" value="00017" />
<option name="presentableId" value="LOCAL-00017" />
<option name="project" value="LOCAL" />
<updated>1722975690755</updated>
</task>
<task id="LOCAL-00018" summary="Add Staff Application Form handling&#10;&#10;Introduced `StaffAppController` and `StaffAppFormData` to handle staff application form submissions. The controller now stores user data, initiates email verification, and provides appropriate responses based on the verification outcome. Additionally, updated `application.properties` and cleaned up IntelliJ workspace.xml.">
<option name="closed" value="true" />
<created>1722975703502</created>
<option name="number" value="00018" />
<option name="presentableId" value="LOCAL-00018" />
<option name="project" value="LOCAL" />
<updated>1722975703502</updated>
</task>
<task id="LOCAL-00019" summary="Add REST annotations to StaffAppController&#10;&#10;Introduce `@RestController` and `@RequestMapping` annotations to the `StaffAppController` class. This change standardizes the API endpoint and ensures all methods within this class are mapped correctly under `/api/apply`.">
<option name="closed" value="true" />
<created>1722975785066</created>
<option name="number" value="00019" />
<option name="presentableId" value="LOCAL-00019" />
<option name="project" value="LOCAL" />
<updated>1722975785066</updated>
</task>
<task id="LOCAL-00020" summary="Update CORS allowed origins configuration&#10;&#10;Consolidated the allowed origins into a single `allowedOrigins` call. This ensures both local and production environments are correctly configured for CORS.">
<option name="closed" value="true" />
<created>1722978999091</created>
<option name="number" value="00020" />
<option name="presentableId" value="LOCAL-00020" />
<option name="project" value="LOCAL" />
<updated>1722978999091</updated>
</task>
<task id="LOCAL-00021" summary="Add REST annotations and refactor properties file handling&#10;&#10;Introduced `@RestController` and `@RequestMapping` in `StaffAppController` for standardized API endpoints. Refactored properties file handling in `PropertiesLoader` and `PropertiesWriter` to simplify file creation logic.">
<option name="closed" value="true" />
<created>1722979026190</created>
<option name="number" value="00021" />
<option name="presentableId" value="LOCAL-00021" />
<option name="project" value="LOCAL" />
<updated>1722979026190</updated>
</task>
<task id="LOCAL-00022" summary="Update Jackson config and refactor JSON handling&#10;&#10;Introduced Jackson dependencies to replace Gson for JSON processing. Updated application properties and controllers to handle Jackson-specific exceptions. Refactored form serialization to use Jackson's `ObjectMapper` for better date handling and consistency.">
<option name="closed" value="true" />
<created>1722981496092</created>
<option name="number" value="00022" />
<option name="presentableId" value="LOCAL-00022" />
<option name="project" value="LOCAL" />
<updated>1722981496092</updated>
</task>
<task id="LOCAL-00023" summary="Add getDiscordBotUrl method to form classes&#10;&#10;Implemented getDiscordBotUrl in form classes for dynamic URL handling. Updated VerifyController to use this method for constructing Discord bot URIs. This enhances flexibility and maintainability in form submission handling.">
<option name="closed" value="true" />
<created>1722981675331</created>
<option name="number" value="00023" />
<option name="presentableId" value="LOCAL-00023" />
<option name="project" value="LOCAL" />
<updated>1722981675331</updated>
</task>
<option name="localTasksCounter" value="24" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@ -527,6 +583,14 @@
<MESSAGE value="Refactor logging for better granularity&#10;&#10;Updated logging levels in multiple classes to differentiate between debug and trace information. Improved log messages to support parameterized logs, ensuring sensitive or variable information is handled appropriately without concatenation." />
<MESSAGE value="Enhance logging for mail verification details&#10;&#10;Updated logging to provide more detailed information about user credentials and email actions. This helps in debugging and monitoring mail verification processes more effectively. Adjusted trace messages to include username and password for better traceability." />
<MESSAGE value="Update URI to point to Discord bot endpoint&#10;&#10;Changed the URI in VerifyController to use the Discord bot's endpoint for form submission. This adjustment is part of the process to route form data correctly through the specified internal service." />
<option name="LAST_COMMIT_MESSAGE" value="Update URI to point to Discord bot endpoint&#10;&#10;Changed the URI in VerifyController to use the Discord bot's endpoint for form submission. This adjustment is part of the process to route form data correctly through the specified internal service." />
<MESSAGE value="Rename StoreFormQuery package to forms.form&#10;&#10;Updated the package name for consistency and better categorization. Adjusted imports in related test files to reflect the new package structure." />
<MESSAGE value="Refactor HTML generation in ContactFormData&#10;&#10;Extract the HTML generation logic to a reusable method in the Form class. This change reduces code duplication and enhances maintainability by centralizing the table generation functionality." />
<MESSAGE value="Add Staff Application Form handling&#10;&#10;Introduced `StaffAppController` and `StaffAppFormData` to handle staff application form submissions. The controller now stores user data, initiates email verification, and provides appropriate responses based on the verification outcome. Additionally, updated `application.properties` and cleaned up IntelliJ workspace.xml." />
<MESSAGE value="Add REST annotations to StaffAppController&#10;&#10;Introduce `@RestController` and `@RequestMapping` annotations to the `StaffAppController` class. This change standardizes the API endpoint and ensures all methods within this class are mapped correctly under `/api/apply`." />
<MESSAGE value="Update CORS allowed origins configuration&#10;&#10;Consolidated the allowed origins into a single `allowedOrigins` call. This ensures both local and production environments are correctly configured for CORS." />
<MESSAGE value="Add REST annotations and refactor properties file handling&#10;&#10;Introduced `@RestController` and `@RequestMapping` in `StaffAppController` for standardized API endpoints. Refactored properties file handling in `PropertiesLoader` and `PropertiesWriter` to simplify file creation logic." />
<MESSAGE value="Update Jackson config and refactor JSON handling&#10;&#10;Introduced Jackson dependencies to replace Gson for JSON processing. Updated application properties and controllers to handle Jackson-specific exceptions. Refactored form serialization to use Jackson's `ObjectMapper` for better date handling and consistency." />
<MESSAGE value="Add getDiscordBotUrl method to form classes&#10;&#10;Implemented getDiscordBotUrl in form classes for dynamic URL handling. Updated VerifyController to use this method for constructing Discord bot URIs. This enhances flexibility and maintainability in form submission handling." />
<option name="LAST_COMMIT_MESSAGE" value="Add getDiscordBotUrl method to form classes&#10;&#10;Implemented getDiscordBotUrl in form classes for dynamic URL handling. Updated VerifyController to use this method for constructing Discord bot URIs. This enhances flexibility and maintainability in form submission handling." />
</component>
</project>

View File

@ -27,8 +27,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation group: 'javax.mail', name: 'mail', version: '1.4'
implementation 'org.springframework.boot:spring-boot-starter-logging'
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'org.mariadb.jdbc:mariadb-java-client:2.1.2'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3'
}
test {

View File

@ -6,6 +6,7 @@ import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import java.time.LocalDate;
import java.util.Optional;
public class StaffAppFormData extends Form {
@ -108,6 +109,16 @@ public class StaffAppFormData extends Form {
'}';
}
@Override
public Optional<String> getDiscordBotUrl() {
return Optional.empty();
}
@Override
public String getReceiver() {
return "apply@alttd.com";
}
@Override
public String toHtml() {
String[] fields = {"Username", "Email", "Discord", "PC requirements", "Age", "Pronoun", "Join date", "Avg time", "Available days", "Available time", "Staff experience", "Plugin experience", "Why staff", "Expectations mod", "Other"};

View File

@ -15,8 +15,7 @@ public class WebConfig implements WebMvcConfigurer { //TODO this can be done wit
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:3000")
.allowedOrigins("https://forms.alttd.com")
.allowedOrigins("http://localhost:3000", "https://forms.alttd.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true);

View File

@ -6,6 +6,8 @@ import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Length;
import java.util.Optional;
public class ContactFormData extends Form {
public ContactFormData(String username, String email, String question) {
@ -36,6 +38,16 @@ public class ContactFormData extends Form {
'}';
}
@Override
public Optional<String> getDiscordBotUrl() {
return Optional.of("http://discordbot:8001/api/contact/submitContactForm");
}
@Override
public String getReceiver() {
return "support@alttd.com";
}
@Override
public String toHtml() {
String[] fields = {"Username", "Email", "Question"};

View File

@ -1,11 +1,17 @@
package com.alttd.forms.form;
import com.google.gson.Gson;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.util.Optional;
public abstract class Form {
public String toJsonString() {
return new Gson().toJson(this);
public String toJsonString() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
return objectMapper.writeValueAsString(this);
}
public abstract String toHtml();
@ -31,4 +37,8 @@ public abstract class Form {
@Override
public abstract String toString();
public abstract Optional<String> getDiscordBotUrl();
public abstract String getReceiver();
}

View File

@ -8,6 +8,7 @@ import java.util.Optional;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -41,6 +42,9 @@ public class StoreFormQuery {
} catch (SQLException e) {
logger.error("Failed insert form query for: " + form, e);
return Optional.empty();
} catch (JsonProcessingException e) {
logger.error("Invalid class for JSON, failed insert form query for: " + form, e);
return Optional.empty();
}
}

View File

@ -26,7 +26,7 @@ public class PropertiesLoader {
}
file = new File(currentJarPath.get(), fileName);
} else {
file = Path.of(URI.create("file://" + path + File.separator + fileName)).toFile();
file = new File(path, fileName);
}

View File

@ -25,7 +25,7 @@ public class PropertiesWriter {
}
file = new File(currentJarPath.get(), fileName);
} else {
file = Path.of(URI.create("file://" + path + File.separator + fileName)).toFile();
file = new File(path, fileName);
}
if (file.exists()) {

View File

@ -3,7 +3,9 @@ package com.alttd.forms.verify_mail;
import com.alttd.forms.contact.ContactFormData;
import com.alttd.forms.database.DatabaseConnection;
import com.alttd.forms.form.Form;
import com.google.gson.Gson;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -53,6 +55,9 @@ public class FormQuery {
} catch (IllegalArgumentException e) {
logger.error("Invalid form class in database", e);
return Optional.empty();
} catch (JsonProcessingException e) {
logger.error("Invalid form json in database", e);
return Optional.empty();
}
} catch (SQLException e) {
logger.error("Failed select form query for form with id: {}", formId, e);
@ -60,10 +65,12 @@ public class FormQuery {
}
}
private Form getForm(String className, String json) throws IllegalArgumentException {
private Form getForm(String className, String json) throws IllegalArgumentException, JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
switch (className) {
case "ContactFormData" -> {
return new Gson().fromJson(json, ContactFormData.class);
return objectMapper.readValue(json, ContactFormData.class);
}
default -> throw new IllegalArgumentException("Invalid form class name: " + className);
}

View File

@ -1,6 +1,8 @@
package com.alttd.forms.verify_mail;
import com.alttd.forms.form.Form;
import com.alttd.forms.mail.mail_forms.MailForm;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -17,6 +19,7 @@ import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@RestController
@ -31,35 +34,53 @@ public class VerifyController {
logger.trace("verificationData: {}", verificationData);
return new FormQuery().getFormForCode(verificationData.code, verificationData.eMail).thenApply(result -> result.form()
.map(form -> {
try {
HttpRequest request = HttpRequest.newBuilder()
//Discord bot url
.uri(new URI("http://discordbot:8001/api/contact/submitContactForm"))//TODO get uri from form
.header("Content-Type", "application/json;charset=UTF-8")
.POST(HttpRequest.BodyPublishers.ofString(form.toJsonString(), StandardCharsets.UTF_8))
.build();
logger.trace("request: {}", request);
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
logger.trace("response: {}", response);
if (response.statusCode() < 200 || response.statusCode() > 200) {
logger.error(String.format("Failed to send form to Discord. Got status code [%d], with body\n%s", response.statusCode(), response.body()));
//TODO handle failure
//TODO strings to config
return ResponseEntity.ok("Failed to send form to Discord, please contact us at admin@alttd.com");
Optional<String> discordBotUrl = form.getDiscordBotUrl();
if (discordBotUrl.isPresent()){
Optional<ResponseEntity<String>> stringResponseEntity = sendDiscordMessage(discordBotUrl.get(), form);
if (stringResponseEntity.isPresent()){
return stringResponseEntity.get();
}
} catch (URISyntaxException e) {
logger.error("Unable to create URI for posting form", e); //TODO more clear
return ResponseEntity.ok("Unable to create URI for posting form, please contact us at admin@alttd.com");
} catch (IOException | InterruptedException e) {
logger.error("Unable to send form to Discord", e); //TODO more clear
}
MailForm.sendForm(form.getReceiver(), form);
try {
return ResponseEntity.ok(form.toJsonString());
} catch (JsonProcessingException e) {
logger.error("Unable to send form to Discord, invalid JSON", e);
return ResponseEntity.ok("Unable to send form to Discord, please contact us at admin@alttd.com");
}
MailForm.sendForm("akastijn@alttd.com", form);
return ResponseEntity.ok(form.toJsonString());
})
.orElse(ResponseEntity.ok(result.failReason()))
).exceptionally(throwable -> ResponseEntity.internalServerError()
.body("The server was unable to process your request, if this issue persists please contact admin@alttd.com"));
}
private Optional<ResponseEntity<String>> sendDiscordMessage(String discordBotUrl, Form form) {
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(discordBotUrl))
.header("Content-Type", "application/json;charset=UTF-8")
.POST(HttpRequest.BodyPublishers.ofString(form.toJsonString(), StandardCharsets.UTF_8))
.build();
logger.trace("request: {}", request);
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
logger.trace("response: {}", response);
if (response.statusCode() < 200 || response.statusCode() > 200) {
logger.error(String.format("Failed to send form to Discord. Got status code [%d], with body\n%s", response.statusCode(), response.body()));
//TODO handle failure
//TODO strings to config
return Optional.of(ResponseEntity.ok("Failed to send form to Discord, please contact us at admin@alttd.com"));
}
} catch (URISyntaxException e) {
logger.error("Unable to create URI for posting form", e); //TODO more clear
return Optional.of(ResponseEntity.ok("Unable to create URI for posting form, please contact us at admin@alttd.com"));
} catch (JsonProcessingException e) {
logger.error("Unable to send form to Discord, invalid JSON", e);
return Optional.of(ResponseEntity.ok("Unable to send form to Discord, please contact us at admin@alttd.com"));
} catch (IOException | InterruptedException e) {
logger.error("Unable to send form to Discord", e); //TODO more clear
return Optional.of(ResponseEntity.ok("Unable to send form to Discord, please contact us at admin@alttd.com"));
}
return Optional.empty();
}
}

View File

@ -1,3 +1,4 @@
logging.level.com.alttd.forms=warn
server.port=8002
spring.jackson.date-format=yyyy-MM-dd
spring.jackson.date-format=yyyy-MM-dd
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false