Refactor code to use Form objects instead of JSON strings
Several parts of the code have been altered to use Form objects instead of JSON strings. Changes include updating the FormQueryResult record type to hold an Optional<Form> instead of an Optional<String>, altering methods in the StoreFormQuery class to insert Form data into the database and replacing JSON handling methods in the FormQuery class with Form object oriented methods. A 'form_class' field has also been added to the 'form' table in the database to aid form identification and reconstruction from stored data.
This commit is contained in:
parent
2b908b4e94
commit
0464281a38
|
|
@ -21,7 +21,7 @@ public class ContactController {
|
||||||
public CompletableFuture<ResponseEntity<String>> submitForm(@Valid @RequestBody ContactFormData formData) {
|
public CompletableFuture<ResponseEntity<String>> submitForm(@Valid @RequestBody ContactFormData formData) {
|
||||||
logger.debug(formData.toString());
|
logger.debug(formData.toString());
|
||||||
|
|
||||||
CompletableFuture<Integer> storeFormForVerificationCode = new StoreFormQuery().storeFormForVerificationCode(formData.toJsonString(), formData.email);
|
CompletableFuture<Integer> storeFormForVerificationCode = new StoreFormQuery().storeFormForVerificationCode(formData.email, formData);
|
||||||
return storeFormForVerificationCode.thenCompose(code -> Verify.verifyEmail(formData.email, code).thenApply(verificationResult -> {
|
return storeFormForVerificationCode.thenCompose(code -> Verify.verifyEmail(formData.email, code).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
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import java.time.Instant;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import com.alttd.forms.form.Form;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
@ -19,11 +21,12 @@ public class StoreFormQuery {
|
||||||
return 100000 + random.nextInt(900000);
|
return 100000 + random.nextInt(900000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<Long> insertForm(Connection connection, String form) {
|
private Optional<Long> insertForm(Connection connection, Form form) {
|
||||||
String insertForm = "INSERT INTO form (creation_date, form_json) VALUES (?, ?)";
|
String insertForm = "INSERT INTO form (creation_date, form_json, form_class) 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);
|
stmt.setString(2, form.toJsonString());
|
||||||
|
stmt.setString(3, form.getClass().getSimpleName());
|
||||||
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);
|
||||||
|
|
@ -57,7 +60,7 @@ public class StoreFormQuery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompletableFuture<Integer> storeFormForVerificationCode(String form, String eMail) {
|
public CompletableFuture<Integer> storeFormForVerificationCode(String eMail, Form form) {
|
||||||
Connection connection = DatabaseConnection.getConnection();
|
Connection connection = DatabaseConnection.getConnection();
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
Optional<Long> optionalFormId = insertForm(connection, form);
|
Optional<Long> optionalFormId = insertForm(connection, form);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ public class Database {
|
||||||
public static void createTables() {
|
public static void createTables() {
|
||||||
String[] createTables = {
|
String[] createTables = {
|
||||||
"CREATE TABLE IF NOT EXISTS verify_form (e_mail VARCHAR(256), verification_code INT, formId INT, PRIMARY KEY(e_mail, verification_code))",
|
"CREATE TABLE IF NOT EXISTS verify_form (e_mail VARCHAR(256), verification_code INT, formId INT, PRIMARY KEY(e_mail, verification_code))",
|
||||||
"CREATE TABLE IF NOT EXISTS form (formId INT AUTO_INCREMENT, creation_date BIGINT, form_json TEXT, PRIMARY KEY(formId))"
|
"CREATE TABLE IF NOT EXISTS form (formId INT AUTO_INCREMENT, creation_date BIGINT, form_json TEXT, form_class VARCHAR(64), PRIMARY KEY(formId))"
|
||||||
};
|
};
|
||||||
Connection connection = DatabaseConnection.getConnection();
|
Connection connection = DatabaseConnection.getConnection();
|
||||||
for (String query : createTables) {
|
for (String query : createTables) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
package com.alttd.forms.mail.mail_forms;
|
package com.alttd.forms.mail.mail_forms;
|
||||||
|
|
||||||
import com.alttd.forms.contact.ContactFormData;
|
|
||||||
import com.alttd.forms.form.Form;
|
import com.alttd.forms.form.Form;
|
||||||
import com.alttd.forms.mail.MailSettings;
|
import com.alttd.forms.mail.MailSettings;
|
||||||
import com.google.gson.Gson;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
@ -17,19 +15,16 @@ 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, String json) { //TODO something to convert json back to the right object, might need to store classname in db?
|
public static void sendForm(String receiver, Form form) {
|
||||||
ContactFormData contactFormData = new Gson().fromJson(json, ContactFormData.class);
|
|
||||||
Properties mailProperties = MailSettings.getMailProperties();
|
Properties mailProperties = MailSettings.getMailProperties();
|
||||||
Optional<PasswordAuthentication> accountDetails = MailSettings.getAccountDetails();
|
Optional<PasswordAuthentication> accountDetails = MailSettings.getAccountDetails();
|
||||||
if (accountDetails.isEmpty()) {
|
if (accountDetails.isEmpty()) {
|
||||||
logger.error("No account details, can't send email to " + receiver + " with data " + contactFormData.toString());
|
logger.error("No account details, can't send email to " + receiver + " with data " + form.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PasswordAuthentication passwordAuthentication = accountDetails.get();
|
PasswordAuthentication passwordAuthentication = accountDetails.get();
|
||||||
Session session = MailSettings.getSession(mailProperties, passwordAuthentication);
|
Session session = MailSettings.getSession(mailProperties, passwordAuthentication);
|
||||||
|
|
||||||
//TODO rate limiting should be handled before anything ever gets here
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Message message = new MimeMessage(session);
|
Message message = new MimeMessage(session);
|
||||||
message.setFrom(new InternetAddress(passwordAuthentication.getUserName()));
|
message.setFrom(new InternetAddress(passwordAuthentication.getUserName()));
|
||||||
|
|
@ -39,12 +34,12 @@ public class MailForm {
|
||||||
);
|
);
|
||||||
message.setSubject("Altitude Form");
|
message.setSubject("Altitude Form");
|
||||||
//TODO add something above the html form probably
|
//TODO add something above the html form probably
|
||||||
message.setContent(contactFormData.toHtml(), "text/html");
|
message.setContent(form.toHtml(), "text/html");
|
||||||
try {
|
try {
|
||||||
Transport.send(message);
|
Transport.send(message);
|
||||||
logger.debug("Send mail to " + receiver + " containing " + contactFormData) ;
|
logger.debug("Send mail to " + receiver + " containing " + form) ;
|
||||||
} catch (MessagingException e) {
|
} catch (MessagingException e) {
|
||||||
logger.error("Unable to send mail to " + receiver + " with data " + contactFormData, e);
|
logger.error("Unable to send mail to " + receiver + " with data " + form, e);
|
||||||
}
|
}
|
||||||
} catch (MessagingException e) {
|
} catch (MessagingException e) {
|
||||||
logger.error("Failed to create MimeMessage", e);
|
logger.error("Failed to create MimeMessage", e);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
package com.alttd.forms.verify_mail;
|
package com.alttd.forms.verify_mail;
|
||||||
|
|
||||||
|
import com.alttd.forms.contact.ContactFormData;
|
||||||
|
import com.alttd.forms.contact.StoreFormQuery;
|
||||||
import com.alttd.forms.database.DatabaseConnection;
|
import com.alttd.forms.database.DatabaseConnection;
|
||||||
|
import com.alttd.forms.form.Form;
|
||||||
|
import com.google.gson.Gson;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
@ -15,7 +19,7 @@ public class FormQuery {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(FormQuery.class);
|
private static final Logger logger = LoggerFactory.getLogger(FormQuery.class);
|
||||||
|
|
||||||
public static Optional<Integer> getFormId(Connection connection, int verificationCode, String eMail) throws SQLException {
|
public Optional<Integer> getFormId(Connection connection, int verificationCode, String eMail) throws SQLException {
|
||||||
String sql = "SELECT formId FROM verify_form WHERE verification_code = ? AND e_mail = ?";
|
String sql = "SELECT formId FROM verify_form WHERE verification_code = ? AND e_mail = ?";
|
||||||
|
|
||||||
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||||
|
|
@ -33,7 +37,7 @@ public class FormQuery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Optional<String> getFormForId(Connection connection, int formId) throws SQLException {
|
private Optional<Form> getFormForId(Connection connection, int formId) throws SQLException {
|
||||||
String sql = "SELECT form_json FROM form WHERE formId = ?";
|
String sql = "SELECT form_json FROM form WHERE formId = ?";
|
||||||
|
|
||||||
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||||
|
|
@ -43,14 +47,30 @@ public class FormQuery {
|
||||||
logger.warn("Could not find form with id: " + formId);
|
logger.warn("Could not find form with id: " + formId);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
return Optional.of(resultSet.getString("form_json"));
|
String json = resultSet.getString("form_json");
|
||||||
|
String formClass = resultSet.getString("form_class");
|
||||||
|
try {
|
||||||
|
return Optional.of(getForm(formClass, json));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
logger.error("Invalid form class in database", e);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
logger.error("Failed select form query for form with id: " + formId, e);
|
logger.error("Failed select form query for form with id: " + formId, e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompletableFuture<FormQueryResult> getFormForCode(String verificationCode, String eMail) {
|
private Form getForm(String className, String json) throws IllegalArgumentException {
|
||||||
|
switch (className) {
|
||||||
|
case "ContactFormData" -> {
|
||||||
|
return new Gson().fromJson(json, ContactFormData.class);
|
||||||
|
}
|
||||||
|
default -> throw new IllegalArgumentException("Invalid form class name: " + className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<FormQueryResult> getFormForCode(String verificationCode, String eMail) {
|
||||||
Connection connection = DatabaseConnection.getConnection();
|
Connection connection = DatabaseConnection.getConnection();
|
||||||
int code;
|
int code;
|
||||||
try {
|
try {
|
||||||
|
|
@ -73,7 +93,7 @@ public class FormQuery {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return getFormForId(connection, formId.get())
|
return getFormForId(connection, formId.get())
|
||||||
.map(formJson -> new FormQueryResult(Optional.of(formJson), "Success"))
|
.map(form -> new FormQueryResult(Optional.of(form), "Success"))
|
||||||
.orElse(new FormQueryResult(Optional.empty(), "Unable to find your form"));
|
.orElse(new FormQueryResult(Optional.empty(), "Unable to find your form"));
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.alttd.forms.verify_mail;
|
package com.alttd.forms.verify_mail;
|
||||||
|
|
||||||
|
import com.alttd.forms.form.Form;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public record FormQueryResult(Optional<String> formJson, String failReason) {
|
public record FormQueryResult(Optional<Form> form, String failReason) {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.alttd.forms.verify_mail;
|
package com.alttd.forms.verify_mail;
|
||||||
|
|
||||||
|
import com.alttd.forms.form.Form;
|
||||||
import com.alttd.forms.mail.mail_forms.MailForm;
|
import com.alttd.forms.mail.mail_forms.MailForm;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
@ -21,12 +22,12 @@ public class VerifyController {
|
||||||
@PostMapping("/form")
|
@PostMapping("/form")
|
||||||
public CompletableFuture<ResponseEntity<String>> validateEmailFromForm(@Valid @RequestBody VerificationData verificationData) {
|
public CompletableFuture<ResponseEntity<String>> validateEmailFromForm(@Valid @RequestBody VerificationData verificationData) {
|
||||||
logger.debug(verificationData.toString());
|
logger.debug(verificationData.toString());
|
||||||
return FormQuery.getFormForCode(verificationData.code, verificationData.eMail).thenApply(form -> form.formJson()
|
return new FormQuery().getFormForCode(verificationData.code, verificationData.eMail).thenApply(result -> result.form()
|
||||||
.map(body -> {
|
.map(form -> {
|
||||||
MailForm.sendForm("akastijn@alttd.com", body);
|
MailForm.sendForm("akastijn@alttd.com", form);
|
||||||
return ResponseEntity.ok(body);
|
return ResponseEntity.ok(form.toJsonString());
|
||||||
})
|
})
|
||||||
.orElse(ResponseEntity.ok(form.failReason()))
|
.orElse(ResponseEntity.ok(result.failReason()))
|
||||||
).exceptionally(throwable -> ResponseEntity.internalServerError()
|
).exceptionally(throwable -> ResponseEntity.internalServerError()
|
||||||
.body("The server was unable to process your request, if this issue persists please contact admin@alttd.com"));
|
.body("The server was unable to process your request, if this issue persists please contact admin@alttd.com"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user