Compare commits
7
Commits
rate_limit
...
3eb4970407
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3eb4970407 | ||
|
|
ab74360571 | ||
|
|
fcda4c9e53 | ||
|
|
4a0aebce82 | ||
|
|
47f6eebd8b | ||
|
|
1dbb80e5a2 | ||
|
|
ed098513f5 |
Generated
+60
-15
@@ -4,11 +4,9 @@
|
|||||||
<option name="autoReloadType" value="SELECTIVE" />
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="ce59df2a-8d56-446a-867b-80e627daf479" name="Changes" comment="Ensure NOT NULL constraints in SQL tables Refactor SQL table creation scripts to add NOT NULL constraints where necessary. This change ensures data integrity by preventing null values in critical columns across the 'verify_form', 'form', 'rate_limit', and 'form_active' tables.">
|
<list default="true" id="ce59df2a-8d56-446a-867b-80e627daf479" name="Changes" comment="Add IP address tracking for form submissions Included IP and timestamp columns in the database schema to track form submissions. Updated methods to handle and store the IP information upon form submission. Adjusted related test cases to validate the new implementation.">
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/com/alttd/forms/controlers/form_active/BooleanResponse.java" afterDir="false" />
|
<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/controlers/form_active/FormActiveController.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/alttd/forms/controlers/form_active/FormActiveController.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/java/com/alttd/forms/controlers/form_active/FormActiveData.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/alttd/forms/controlers/form_active/FormActiveData.java" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/resources/application.properties" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/resources/application.properties" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@@ -53,6 +51,7 @@
|
|||||||
<option value="package.json" />
|
<option value="package.json" />
|
||||||
<option value="Class" />
|
<option value="Class" />
|
||||||
<option value="Record" />
|
<option value="Record" />
|
||||||
|
<option value="Interface" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
@@ -79,6 +78,14 @@
|
|||||||
"accountId": "ad9eb076-a98f-40c2-b7e5-9fc28b23038f"
|
"accountId": "ad9eb076-a98f-40c2-b7e5-9fc28b23038f"
|
||||||
}
|
}
|
||||||
}</component>
|
}</component>
|
||||||
|
<component name="HighlightingSettingsPerFile">
|
||||||
|
<setting file="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/javax.mail/mail/1.4/1aa1579ae5ecd41920c4f355b0a9ef40b68315dd/mail-1.4.jar!/javax/mail/Part.class" root0="SKIP_INSPECTION" />
|
||||||
|
</component>
|
||||||
|
<component name="Jenkins.Settings">
|
||||||
|
<option name="jenkinsUrl" value="https://jenkins.alttd.com" />
|
||||||
|
<option name="lastSelectedView" value="all" />
|
||||||
|
<option name="username" value="stijn" />
|
||||||
|
</component>
|
||||||
<component name="KubernetesApiProvider">{
|
<component name="KubernetesApiProvider">{
|
||||||
"isMigrated": true
|
"isMigrated": true
|
||||||
}</component>
|
}</component>
|
||||||
@@ -120,10 +127,9 @@
|
|||||||
"RequestMappingsPanelWidth1": "75",
|
"RequestMappingsPanelWidth1": "75",
|
||||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
|
||||||
"Spring Boot.Main.executor": "Run",
|
"Spring Boot.Main.executor": "Run",
|
||||||
"Tomcat Server.Tomcat 10.1.17.executor": "Run",
|
"Tomcat Server.Tomcat 10.1.17.executor": "Run",
|
||||||
"git-widget-placeholder": "rate__limit",
|
"git-widget-placeholder": "master",
|
||||||
"ignore.virus.scanning.warn.message": "true",
|
"ignore.virus.scanning.warn.message": "true",
|
||||||
"kotlin-language-version-configured": "true",
|
"kotlin-language-version-configured": "true",
|
||||||
"last_opened_file_path": "P:/Code/Plugins/forms",
|
"last_opened_file_path": "P:/Code/Plugins/forms",
|
||||||
@@ -136,7 +142,7 @@
|
|||||||
"project.structure.proportion": "0.0",
|
"project.structure.proportion": "0.0",
|
||||||
"project.structure.side.proportion": "0.0",
|
"project.structure.side.proportion": "0.0",
|
||||||
"run.code.analysis.last.selected.profile": "pProject Default",
|
"run.code.analysis.last.selected.profile": "pProject Default",
|
||||||
"settings.editor.selected.configurable": "preferences.lookFeel",
|
"settings.editor.selected.configurable": "org.codinjutsu.tools.jenkins.servers",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"vue.rearranger.settings.migration": "true"
|
||||||
},
|
},
|
||||||
"keyToStringList": {
|
"keyToStringList": {
|
||||||
@@ -385,6 +391,9 @@
|
|||||||
<workItem from="1723138548381" duration="1949000" />
|
<workItem from="1723138548381" duration="1949000" />
|
||||||
<workItem from="1723230192640" duration="55000" />
|
<workItem from="1723230192640" duration="55000" />
|
||||||
<workItem from="1723242314809" duration="9799000" />
|
<workItem from="1723242314809" duration="9799000" />
|
||||||
|
<workItem from="1723307861750" duration="2179000" />
|
||||||
|
<workItem from="1723392202182" duration="258000" />
|
||||||
|
<workItem from="1723392471077" duration="2183000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="Initial commit for site for forms">
|
<task id="LOCAL-00001" summary="Initial commit for site for forms">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
@@ -650,7 +659,39 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1723249968746</updated>
|
<updated>1723249968746</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="34" />
|
<task id="LOCAL-00034" summary="Add branch condition to Discord notification stage The Discord notification stage now runs only on 'main' or 'master' branches. This helps to avoid unnecessary notifications for feature or bugfix branches.">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1723392636255</created>
|
||||||
|
<option name="number" value="00034" />
|
||||||
|
<option name="presentableId" value="LOCAL-00034" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1723392636255</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00035" summary="Improve email handling with Mailable interface Added a new Mailable interface for extracting email-related data like receiver and subject. Updated StaffAppFormData and ContactFormData to implement this interface, and refactored MailForm to utilize these details. This enhances flexibility and decouples email details from form classes.">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1723393276632</created>
|
||||||
|
<option name="number" value="00035" />
|
||||||
|
<option name="presentableId" value="LOCAL-00035" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1723393276632</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00036" summary="Update `toHtml()` method in `Form.java` Simplified the HTML structure for the `toHtml` method by switching from a table layout to paragraph tags. This removes unnecessary table formatting for improved readability and maintainability. Also updated workspace.xml with task tracking and removed outdated comments.">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1723393478027</created>
|
||||||
|
<option name="number" value="00036" />
|
||||||
|
<option name="presentableId" value="LOCAL-00036" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1723393478027</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00037" summary="Add IP address tracking for form submissions Included IP and timestamp columns in the database schema to track form submissions. Updated methods to handle and store the IP information upon form submission. Adjusted related test cases to validate the new implementation.">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1723393877624</created>
|
||||||
|
<option name="number" value="00037" />
|
||||||
|
<option name="presentableId" value="LOCAL-00037" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1723393877624</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="38" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@@ -668,11 +709,6 @@
|
|||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="VcsManagerConfiguration">
|
<component name="VcsManagerConfiguration">
|
||||||
<MESSAGE value="Configure system property for conditional test execution Added a system property 'doNotRunDatabaseTests' in the test configuration to allow conditional skipping of database tests. This helps in running tests selectively during different build scenarios." />
|
|
||||||
<MESSAGE value="Add CORS support for production server Updated the CORS configuration to include the production server URL. This change ensures that requests from the production environment are properly handled." />
|
|
||||||
<MESSAGE value="Refactor logging for better granularity 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 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 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 Updated the package name for consistency and better categorization. Adjusted imports in related test files to reflect the new package structure." />
|
<MESSAGE value="Rename StoreFormQuery package to forms.form 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 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="Refactor HTML generation in ContactFormData 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 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 Staff Application Form handling 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." />
|
||||||
@@ -693,6 +729,15 @@
|
|||||||
<MESSAGE value="Refactor form request handling and add rate limiting. Consolidate email verification logic into FormRequestHandler to simplify code maintenance. Implement a new rate limiting feature to restrict form submissions based on IP and email address, improving server security and performance." />
|
<MESSAGE value="Refactor form request handling and add rate limiting. Consolidate email verification logic into FormRequestHandler to simplify code maintenance. Implement a new rate limiting feature to restrict form submissions based on IP and email address, improving server security and performance." />
|
||||||
<MESSAGE value="Add form activity checking and global rate limiting Implemented new features to track form activity and enforce global rate limits. Added a `form_active` table and created endpoints to check form activity. Also, introduced a rate-limiting filter to restrict API requests to 30 per minute per IP." />
|
<MESSAGE value="Add form activity checking and global rate limiting Implemented new features to track form activity and enforce global rate limits. Added a `form_active` table and created endpoints to check form activity. Also, introduced a rate-limiting filter to restrict API requests to 30 per minute per IP." />
|
||||||
<MESSAGE value="Ensure NOT NULL constraints in SQL tables Refactor SQL table creation scripts to add NOT NULL constraints where necessary. This change ensures data integrity by preventing null values in critical columns across the 'verify_form', 'form', 'rate_limit', and 'form_active' tables." />
|
<MESSAGE value="Ensure NOT NULL constraints in SQL tables Refactor SQL table creation scripts to add NOT NULL constraints where necessary. This change ensures data integrity by preventing null values in critical columns across the 'verify_form', 'form', 'rate_limit', and 'form_active' tables." />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="Ensure NOT NULL constraints in SQL tables Refactor SQL table creation scripts to add NOT NULL constraints where necessary. This change ensures data integrity by preventing null values in critical columns across the 'verify_form', 'form', 'rate_limit', and 'form_active' tables." />
|
<MESSAGE value="Add JSON response handling for form activity check Refactor `FormActiveController` to return JSON responses using `BooleanResponse`. Introduce exception handling for JSON processing errors and update `FormActiveData` to allow object initialization without parameters." />
|
||||||
|
<MESSAGE value="Add branch condition to Discord notification stage The Discord notification stage now runs only on 'main' or 'master' branches. This helps to avoid unnecessary notifications for feature or bugfix branches." />
|
||||||
|
<MESSAGE value="Improve email handling with Mailable interface Added a new Mailable interface for extracting email-related data like receiver and subject. Updated StaffAppFormData and ContactFormData to implement this interface, and refactored MailForm to utilize these details. This enhances flexibility and decouples email details from form classes." />
|
||||||
|
<MESSAGE value="Update `toHtml()` method in `Form.java` Simplified the HTML structure for the `toHtml` method by switching from a table layout to paragraph tags. This removes unnecessary table formatting for improved readability and maintainability. Also updated workspace.xml with task tracking and removed outdated comments." />
|
||||||
|
<MESSAGE value="Add IP address tracking for form submissions Included IP and timestamp columns in the database schema to track form submissions. Updated methods to handle and store the IP information upon form submission. Adjusted related test cases to validate the new implementation." />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="Add IP address tracking for form submissions Included IP and timestamp columns in the database schema to track form submissions. Updated methods to handle and store the IP information upon form submission. Adjusted related test cases to validate the new implementation." />
|
||||||
|
</component>
|
||||||
|
<component name="XSLT-Support.FileAssociations.UIState">
|
||||||
|
<expand />
|
||||||
|
<select />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Vendored
+6
@@ -12,6 +12,12 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('discord') {
|
stage('discord') {
|
||||||
|
when {
|
||||||
|
anyOf {
|
||||||
|
branch 'main'
|
||||||
|
branch 'master'
|
||||||
|
}
|
||||||
|
}
|
||||||
steps {
|
steps {
|
||||||
discordSend description: "Build: ${BUILD_NUMBER}", showChangeset: true, result: currentBuild.currentResult, title: currentBuild.fullProjectName, webhookURL: env.discordwebhook
|
discordSend description: "Build: ${BUILD_NUMBER}", showChangeset: true, result: currentBuild.currentResult, title: currentBuild.fullProjectName, webhookURL: env.discordwebhook
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public class FormRequestHandler {
|
|||||||
private static final Logger logger = LoggerFactory.getLogger(FormRequestHandler.class);
|
private static final Logger logger = LoggerFactory.getLogger(FormRequestHandler.class);
|
||||||
|
|
||||||
public static CompletableFuture<ResponseEntity<String>> handleRequestWithVerifyMail(Form form, String ip) {
|
public static CompletableFuture<ResponseEntity<String>> handleRequestWithVerifyMail(Form form, String ip) {
|
||||||
CompletableFuture<Integer> storeFormForVerificationCode = new StoreFormQuery().storeFormForVerificationCode(form.getSender(), form);
|
CompletableFuture<Integer> storeFormForVerificationCode = new StoreFormQuery().storeFormForVerificationCode(form.getSender(), form, ip);
|
||||||
return storeFormForVerificationCode.thenCompose(code -> Verify.verifyEmail(ip, form.getSender(), code, form).thenApply(verificationResult -> {
|
return storeFormForVerificationCode.thenCompose(code -> Verify.verifyEmail(ip, form.getSender(), code, form).thenApply(verificationResult -> {
|
||||||
if (verificationResult == VerificationResult.VERIFICATION_SENT) {
|
if (verificationResult == VerificationResult.VERIFICATION_SENT) {
|
||||||
//TODO if this is ok tell the user they have x min to verify if they fail to do so they have to remake the form
|
//TODO if this is ok tell the user they have x min to verify if they fail to do so they have to remake the form
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.alttd.forms.controlers.apply;
|
package com.alttd.forms.controlers.apply;
|
||||||
|
|
||||||
import com.alttd.forms.form.Form;
|
import com.alttd.forms.form.Form;
|
||||||
|
import com.alttd.forms.mail.mail_forms.Mailable;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import jakarta.validation.constraints.*;
|
import jakarta.validation.constraints.*;
|
||||||
import org.hibernate.validator.constraints.Length;
|
import org.hibernate.validator.constraints.Length;
|
||||||
import org.hibernate.validator.constraints.Range;
|
import org.hibernate.validator.constraints.Range;
|
||||||
@@ -8,7 +10,9 @@ import org.hibernate.validator.constraints.Range;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class StaffAppFormData extends Form {
|
public class StaffAppFormData extends Form implements Mailable {
|
||||||
|
|
||||||
|
public StaffAppFormData() {}
|
||||||
|
|
||||||
public StaffAppFormData(String username, String email, String discord, String pc_requirements, int age, String pronoun, LocalDate join_date, int avg_time, String available_days, String available_time, String staff_experience, String plugin_experience, String why_staff, String expectations_mod, String other) {
|
public StaffAppFormData(String username, String email, String discord, String pc_requirements, int age, String pronoun, LocalDate join_date, int avg_time, String available_days, String available_time, String staff_experience, String plugin_experience, String why_staff, String expectations_mod, String other) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
@@ -31,63 +35,64 @@ public class StaffAppFormData extends Form {
|
|||||||
@NotEmpty(message = "Username is required")
|
@NotEmpty(message = "Username is required")
|
||||||
@Length(min = 3, max = 16, message = "Username should be between 3 and 16 characters")
|
@Length(min = 3, max = 16, message = "Username should be between 3 and 16 characters")
|
||||||
@Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "Username should only include alphanumeric characters and underscore")
|
@Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "Username should only include alphanumeric characters and underscore")
|
||||||
public final String username;
|
public String username;
|
||||||
|
|
||||||
@NotEmpty(message = "E-mail address is required")
|
@NotEmpty(message = "E-mail address is required")
|
||||||
@Email(message = "Invalid email")
|
@Email(message = "Invalid email")
|
||||||
@Length(min = 3, max = 254, message = "Email should be between 3 and 254 characters")
|
@Length(min = 3, max = 254, message = "Email should be between 3 and 254 characters")
|
||||||
public final String email;
|
public String email;
|
||||||
|
|
||||||
@NotEmpty(message = "Discord name is required")
|
@NotEmpty(message = "Discord name is required")
|
||||||
@Length(min = 2, max = 32, message = "Discord name should be between 2 and 32 characters")
|
@Length(min = 2, max = 32, message = "Discord name should be between 2 and 32 characters")
|
||||||
@Pattern(regexp = "^([a-z0-9._]{2,32})$", message = "Please enter a valid Discord name")
|
@Pattern(regexp = "^([a-z0-9._]{2,32})$", message = "Please enter a valid Discord name")
|
||||||
public final String discord;
|
public String discord;
|
||||||
|
|
||||||
@NotEmpty(message = "An answer is required")
|
@NotEmpty(message = "An answer is required")
|
||||||
@Length(min = 2, max = 3, message = "Please answer yes or no")
|
@Length(min = 2, max = 3, message = "Please answer yes or no")
|
||||||
@Pattern(regexp = "(?i)^(yes|no)$", message = "Yes or no")
|
@Pattern(regexp = "(?i)^(yes|no)$", message = "Yes or no")
|
||||||
public final String pc_requirements;
|
public String pc_requirements;
|
||||||
|
|
||||||
@Min(value = 0, message = "Please enter a valid age")
|
@Min(value = 0, message = "Please enter a valid age")
|
||||||
@Max(value = 999, message = "We do not accept players older than 999 years old sorry!")
|
@Max(value = 999, message = "We do not accept players older than 999 years old sorry!")
|
||||||
public final int age;
|
public int age;
|
||||||
|
|
||||||
@Length(max = 16, message = "Pronouns can't be longer than 16 characters")
|
@Length(max = 16, message = "Pronouns can't be longer than 16 characters")
|
||||||
public final String pronoun;
|
public String pronoun;
|
||||||
|
|
||||||
@NotNull(message = "Your join date is required, if you're not sure enter an estimated date")
|
@NotNull(message = "Your join date is required, if you're not sure enter an estimated date")
|
||||||
public final LocalDate join_date;
|
public LocalDate join_date;
|
||||||
|
|
||||||
@Range(min = 0, max = 168, message = "The only valid values are 0-168")
|
@Range(min = 0, max = 168, message = "The only valid values are 0-168")
|
||||||
public final int avg_time;
|
public int avg_time;
|
||||||
|
|
||||||
@NotEmpty(message = "Available days are required")
|
@NotEmpty(message = "Available days are required")
|
||||||
@Length(min = 6, max = 128, message = "Available days should be between 6 and 128 characters")
|
@Length(min = 6, max = 128, message = "Available days should be between 6 and 128 characters")
|
||||||
public final String available_days;
|
public String available_days;
|
||||||
|
|
||||||
@NotEmpty(message = "Available time is required")
|
@NotEmpty(message = "Available time is required")
|
||||||
@Length(min = 3, max = 256, message = "Available time should be between 3 and 256 characters")
|
@Length(min = 3, max = 256, message = "Available time should be between 3 and 256 characters")
|
||||||
public final String available_time;
|
public String available_time;
|
||||||
|
|
||||||
@NotEmpty(message = "Staff experience is required")
|
@NotEmpty(message = "Staff experience is required")
|
||||||
@Length(min = 2, max = 2000, message = "Experience should be between 2 and 2000 characters")
|
@Length(min = 2, max = 2000, message = "Experience should be between 2 and 2000 characters")
|
||||||
public final String staff_experience;
|
public String staff_experience;
|
||||||
|
|
||||||
@NotEmpty(message = "Plugin experience is required")
|
@NotEmpty(message = "Plugin experience is required")
|
||||||
@Length(min = 2, max = 2000, message = "Experience should be between 2 and 2000 characters")
|
@Length(min = 2, max = 2000, message = "Experience should be between 2 and 2000 characters")
|
||||||
public final String plugin_experience;
|
public String plugin_experience;
|
||||||
|
|
||||||
@NotEmpty(message = "Reason for wanting to be a moderator is required")
|
@NotEmpty(message = "Reason for wanting to be a moderator is required")
|
||||||
@Length(min = 2, max =2000, message = "Reason should be between 2 and 2000 characters")
|
@Length(min = 2, max =2000, message = "Reason should be between 2 and 2000 characters")
|
||||||
public final String why_staff;
|
public String why_staff;
|
||||||
|
|
||||||
@NotEmpty(message = "Expectations of a moderator is required")
|
@NotEmpty(message = "Expectations of a moderator is required")
|
||||||
@Length(min = 2, max = 2000, message = "Expectation should be between 2 and 2000 characters")
|
@Length(min = 2, max = 2000, message = "Expectation should be between 2 and 2000 characters")
|
||||||
public final String expectations_mod;
|
public String expectations_mod;
|
||||||
|
|
||||||
@Length(max = 2000, message = "Text can't be longer than 2000 characters")
|
@Length(max = 2000, message = "Text can't be longer than 2000 characters")
|
||||||
public final String other;
|
public String other;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "StaffAppFormData{" +
|
return "StaffAppFormData{" +
|
||||||
@@ -109,21 +114,31 @@ public class StaffAppFormData extends Form {
|
|||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public Optional<String> getDiscordBotUrl() {
|
public Optional<String> getDiscordBotUrl() {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public String getReceiver() {
|
public String getReceiver() {
|
||||||
return "[email protected]";
|
return "[email protected]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@Override
|
||||||
|
public String getSubject() {
|
||||||
|
return "Staff Application: " + username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public String getSender() {
|
public String getSender() {
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public String toHtml() {
|
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"};
|
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"};
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.alttd.forms.controlers.contact;
|
package com.alttd.forms.controlers.contact;
|
||||||
|
|
||||||
import com.alttd.forms.form.Form;
|
import com.alttd.forms.form.Form;
|
||||||
|
import com.alttd.forms.mail.mail_forms.Mailable;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import jakarta.validation.constraints.Email;
|
import jakarta.validation.constraints.Email;
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import jakarta.validation.constraints.Pattern;
|
import jakarta.validation.constraints.Pattern;
|
||||||
@@ -8,7 +10,9 @@ import org.hibernate.validator.constraints.Length;
|
|||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class ContactFormData extends Form {
|
public class ContactFormData extends Form implements Mailable {
|
||||||
|
|
||||||
|
public ContactFormData() {}
|
||||||
|
|
||||||
public ContactFormData(String username, String email, String question) {
|
public ContactFormData(String username, String email, String question) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
@@ -19,16 +23,17 @@ public class ContactFormData extends Form {
|
|||||||
@NotEmpty(message = "You have to provide a username")
|
@NotEmpty(message = "You have to provide a username")
|
||||||
@Length(min = 3, max = 16, message = "Usernames have to be between 3 and 16 characters")
|
@Length(min = 3, max = 16, message = "Usernames have to be between 3 and 16 characters")
|
||||||
@Pattern(regexp = "[a-zA-Z-0-9_]{3,16}", message = "Your username has to be a valid Minecraft username")
|
@Pattern(regexp = "[a-zA-Z-0-9_]{3,16}", message = "Your username has to be a valid Minecraft username")
|
||||||
public final String username;
|
public String username;
|
||||||
|
|
||||||
@NotEmpty(message = "You have to provide an e-mail address")
|
@NotEmpty(message = "You have to provide an e-mail address")
|
||||||
@Email(regexp = "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)])",
|
@Email(regexp = "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)])",
|
||||||
message = "This is not a valid e-mail address")
|
message = "This is not a valid e-mail address")
|
||||||
public final String email;
|
public String email;
|
||||||
|
|
||||||
@Length(min = 11, max = 2000, message = "Your question should have between 10 and 2000 characters")
|
@Length(min = 11, max = 2000, message = "Your question should have between 10 and 2000 characters")
|
||||||
public final String question;
|
public String question;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ContactFormData{" +
|
return "ContactFormData{" +
|
||||||
@@ -38,21 +43,31 @@ public class ContactFormData extends Form {
|
|||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public Optional<String> getDiscordBotUrl() {
|
public Optional<String> getDiscordBotUrl() {
|
||||||
return Optional.of("http://discordbot:8001/api/contact/submitContactForm");
|
return Optional.of("http://discordbot:8001/api/contact/submitContactForm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public String getReceiver() {
|
public String getReceiver() {
|
||||||
return "[email protected]";
|
return "[email protected]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@Override
|
||||||
|
public String getSubject() {
|
||||||
|
return "Contact form: " + username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public String getSender() {
|
public String getSender() {
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public String toHtml() {
|
public String toHtml() {
|
||||||
String[] fields = {"Username", "Email", "Question"};
|
String[] fields = {"Username", "Email", "Question"};
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import java.sql.SQLException;
|
|||||||
|
|
||||||
public class Database {
|
public class Database {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(Database.class); //TODO can be replaced with library and that one db file that creates the db
|
private static final Logger logger = LoggerFactory.getLogger(Database.class);
|
||||||
|
|
||||||
public static void createTables() {
|
public static void createTables() {
|
||||||
String[] createTables = {
|
String[] createTables = {
|
||||||
@@ -28,6 +28,8 @@ public class Database {
|
|||||||
creation_date BIGINT NOT NULL,
|
creation_date BIGINT NOT NULL,
|
||||||
form_json TEXT NOT NULL,
|
form_json TEXT NOT NULL,
|
||||||
form_class VARCHAR(64) NOT NULL,
|
form_class VARCHAR(64) NOT NULL,
|
||||||
|
ip VARCHAR(45) not null,
|
||||||
|
time TIMESTAMP default current_timestamp() not null,
|
||||||
PRIMARY KEY(formId)
|
PRIMARY KEY(formId)
|
||||||
)
|
)
|
||||||
""",
|
""",
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public abstract class Form {
|
public abstract class Form {
|
||||||
|
|
||||||
@@ -18,25 +20,19 @@ public abstract class Form {
|
|||||||
|
|
||||||
public String toHtml(String[] fields, String[] values) {
|
public String toHtml(String[] fields, String[] values) {
|
||||||
StringBuilder htmlOutput = new StringBuilder();
|
StringBuilder htmlOutput = new StringBuilder();
|
||||||
//language=HTML
|
|
||||||
htmlOutput.append("<table style='border-collapse: collapse; width: 100%;'>");
|
|
||||||
for (int i = 0; i < fields.length; i++) {
|
for (int i = 0; i < fields.length; i++) {
|
||||||
|
String paragraphs = Arrays.stream(values[i].split("\n"))
|
||||||
|
.filter(str -> !str.isBlank())
|
||||||
|
.map(str -> String.format("<p>%s</p>", str))
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
htmlOutput.append(
|
htmlOutput.append(
|
||||||
String.format(
|
String.format(
|
||||||
//language=HTML
|
//language=HTML
|
||||||
"""
|
"""
|
||||||
<tr style='border: 1px solid #ddd;'>
|
<p><strong>%s</strong></p>
|
||||||
<td style='border: 1px solid #ddd; padding: 10px; font-weight: bold;'>
|
<p>%s</p>
|
||||||
%s
|
""", fields[i], paragraphs));
|
||||||
</td>
|
|
||||||
<td style='border: 1px solid #ddd; padding: 10px;'>
|
|
||||||
%s
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
""", fields[i], values[i]));
|
|
||||||
}
|
}
|
||||||
//language=HTML
|
|
||||||
htmlOutput.append("</table>");
|
|
||||||
return htmlOutput.toString();
|
return htmlOutput.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +41,5 @@ public abstract class Form {
|
|||||||
|
|
||||||
public abstract Optional<String> getDiscordBotUrl();
|
public abstract Optional<String> getDiscordBotUrl();
|
||||||
|
|
||||||
public abstract String getReceiver();
|
|
||||||
|
|
||||||
public abstract String getSender();
|
public abstract String getSender();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,29 +21,30 @@ public class StoreFormQuery {
|
|||||||
return 100000 + random.nextInt(900000);
|
return 100000 + random.nextInt(900000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<Long> insertForm(Connection connection, Form form) {
|
private Optional<Long> insertForm(Connection connection, Form form, String ip) {
|
||||||
String insertForm = "INSERT INTO form (creation_date, form_json, form_class) VALUES (?, ?, ?)";
|
String insertForm = "INSERT INTO form (creation_date, form_json, form_class, ip) VALUES (?, ?, ?, ?)";
|
||||||
try (PreparedStatement stmt = connection.prepareStatement(insertForm, Statement.RETURN_GENERATED_KEYS)) {
|
try (PreparedStatement stmt = connection.prepareStatement(insertForm, Statement.RETURN_GENERATED_KEYS)) {
|
||||||
stmt.setLong(1, Instant.now().toEpochMilli());
|
stmt.setLong(1, Instant.now().toEpochMilli());
|
||||||
stmt.setString(2, form.toJsonString());
|
stmt.setString(2, form.toJsonString());
|
||||||
stmt.setString(3, form.getClass().getSimpleName());
|
stmt.setString(3, form.getClass().getSimpleName());
|
||||||
|
stmt.setString(4, ip);
|
||||||
int affectedRows = stmt.executeUpdate();
|
int affectedRows = stmt.executeUpdate();
|
||||||
if (affectedRows == 0) {
|
if (affectedRows == 0) {
|
||||||
logger.error("No rows affected during insert of form: " + form);
|
logger.error("No rows affected during insert of form: {}", form);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
ResultSet generatedKeys = stmt.getGeneratedKeys();
|
ResultSet generatedKeys = stmt.getGeneratedKeys();
|
||||||
if (generatedKeys.next()) {
|
if (generatedKeys.next()) {
|
||||||
return Optional.of(generatedKeys.getLong(1));
|
return Optional.of(generatedKeys.getLong(1));
|
||||||
} else {
|
} else {
|
||||||
logger.error("No primary key generated when inserting form " + form);
|
logger.error("No primary key generated when inserting form {}", form);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
logger.error("Failed insert form query for: " + form, e);
|
logger.error("Failed insert form query for: {}", form, e);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
logger.error("Invalid class for JSON, failed insert form query for: " + form, e);
|
logger.error("Invalid class for JSON, failed insert form query for: {}", form, e);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,17 +59,17 @@ public class StoreFormQuery {
|
|||||||
stmt.executeUpdate();
|
stmt.executeUpdate();
|
||||||
return Optional.of(verificationCode);
|
return Optional.of(verificationCode);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
logger.error("Failed to insert verification code for form with id: " + formId);
|
logger.error("Failed to insert verification code for form with id: {}", formId);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<Integer> storeFormForVerificationCode(String eMail, Form form) {
|
public CompletableFuture<Integer> storeFormForVerificationCode(String eMail, Form form, String ip) {
|
||||||
logger.debug("storeFormForVerificationCode");
|
logger.debug("storeFormForVerificationCode");
|
||||||
Connection connection = DatabaseConnection.getConnection();
|
Connection connection = DatabaseConnection.getConnection();
|
||||||
logger.trace("Connection: {}", connection);
|
logger.trace("Connection: {}", connection);
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
Optional<Long> optionalFormId = insertForm(connection, form);
|
Optional<Long> optionalFormId = insertForm(connection, form, ip);
|
||||||
logger.trace("Form id: {}", optionalFormId);
|
logger.trace("Form id: {}", optionalFormId);
|
||||||
if (optionalFormId.isEmpty()) {
|
if (optionalFormId.isEmpty()) {
|
||||||
throw new RuntimeException("Failed to store form");
|
throw new RuntimeException("Failed to store form");
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ public class MailForm {
|
|||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(MailForm.class);
|
private static final Logger logger = LoggerFactory.getLogger(MailForm.class);
|
||||||
|
|
||||||
public static void sendForm(String receiver, Form form) {
|
public static void sendForm(Form form, Mailable mailable) {
|
||||||
|
String receiver = mailable.getReceiver();
|
||||||
Properties mailProperties = MailSettings.getMailProperties();
|
Properties mailProperties = MailSettings.getMailProperties();
|
||||||
Optional<PasswordAuthentication> accountDetails = MailSettings.getAccountDetails();
|
Optional<PasswordAuthentication> accountDetails = MailSettings.getAccountDetails();
|
||||||
if (accountDetails.isEmpty()) {
|
if (accountDetails.isEmpty()) {
|
||||||
@@ -32,8 +33,7 @@ public class MailForm {
|
|||||||
Message.RecipientType.TO,
|
Message.RecipientType.TO,
|
||||||
InternetAddress.parse(receiver)
|
InternetAddress.parse(receiver)
|
||||||
);
|
);
|
||||||
message.setSubject("Altitude Form");
|
message.setSubject(mailable.getSubject());
|
||||||
//TODO add something above the html form probably
|
|
||||||
message.setContent(form.toHtml(), "text/html");
|
message.setContent(form.toHtml(), "text/html");
|
||||||
try {
|
try {
|
||||||
Transport.send(message);
|
Transport.send(message);
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.alttd.forms.mail.mail_forms;
|
||||||
|
|
||||||
|
public interface Mailable {
|
||||||
|
|
||||||
|
String getReceiver();
|
||||||
|
|
||||||
|
String getSubject();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package com.alttd.forms.verify_mail;
|
package com.alttd.forms.verify_mail;
|
||||||
|
|
||||||
|
import com.alttd.forms.controlers.apply.StaffAppFormData;
|
||||||
import com.alttd.forms.form.Form;
|
import com.alttd.forms.form.Form;
|
||||||
import com.alttd.forms.mail.mail_forms.MailForm;
|
import com.alttd.forms.mail.mail_forms.MailForm;
|
||||||
|
import com.alttd.forms.mail.mail_forms.Mailable;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -41,7 +43,8 @@ public class VerifyController {
|
|||||||
return stringResponseEntity.get();
|
return stringResponseEntity.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MailForm.sendForm(form.getReceiver(), form);
|
if (form instanceof Mailable mailable)
|
||||||
|
MailForm.sendForm(form, mailable);
|
||||||
try {
|
try {
|
||||||
return ResponseEntity.ok(form.toJsonString());
|
return ResponseEntity.ok(form.toJsonString());
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class TestForm {
|
|||||||
Assertions.assertDoesNotThrow(() -> DatabaseConnection.initialize());
|
Assertions.assertDoesNotThrow(() -> DatabaseConnection.initialize());
|
||||||
StoreFormQuery storeFormQuery = new StoreFormQuery();
|
StoreFormQuery storeFormQuery = new StoreFormQuery();
|
||||||
ContactFormData contactFormData = new ContactFormData("akastijn", "[email protected]", "This is a test question.");
|
ContactFormData contactFormData = new ContactFormData("akastijn", "[email protected]", "This is a test question.");
|
||||||
storeFormQuery.storeFormForVerificationCode("[email protected]", contactFormData).
|
storeFormQuery.storeFormForVerificationCode("[email protected]", contactFormData, "0.0.0.0").
|
||||||
thenAccept(code -> {
|
thenAccept(code -> {
|
||||||
TestForm.code = code;
|
TestForm.code = code;
|
||||||
Assertions.assertTrue(code > 999 && code < 10000);
|
Assertions.assertTrue(code > 999 && code < 10000);
|
||||||
|
|||||||
Reference in New Issue
Block a user